All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic translation framework
@ 2017-06-12 14:53 Lluís Vilanova
  2017-06-12 14:53 ` [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
                   ` (5 more replies)
  0 siblings, 6 replies; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-12 14:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alex Bennée, Richard Henderson, Peter Crosthwaite, Paolo Bonzini

This series proposes a generic (target-agnostic) instruction translation
framework.

It basically provides a generic main loop for instruction disassembly, which
calls target-specific functions when necessary. This generalization makes
inserting new code in the main loop easier, and helps in keeping all targets in
synch as to the contents of it.

This series also paves the way towards adding events to trace guest code
execution (BBLs and instructions).

I've ported i386/x86-64 and arm/aarch64 as an example to see how it fits in the
current organization, but will port the rest when this series gets merged.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---

Changes in v6
=============

* Rebase on upstream master (64175afc69).
* Reorder fields in DisasContextBase to minimize padding [Richard Henderson].


Changes in v5
=============

* Remove stray uses of "restrict" keyword.


Changes in v4
=============

* Document new macro QTAILQ_FOREACH_CONTINUE [Peter Maydell].
* Fix coding style errors reported by checkpatch.
* Remove use of "restrict" in added functions; it makes older gcc versions barf
  about compilation errors.


Changes in v3
=============

* Rebase on 0737f32daf.


Changes in v2
=============

* Port ARM and AARCH64 targets.
* Fold single-stepping checks into "max_insns" [Richard Henderson].
* Move instruction start marks to target code [Richard Henderson].
* Add target hook for TB start.
* Check for TCG temporary leaks.
* Move instruction disassembly into a target hook.
* Make breakpoint_hit() return an enum to accomodate target's needs (ARM).


Lluís Vilanova (6):
      Pass generic CPUState to gen_intermediate_code()
      queue: Add macro for incremental traversal
      target: [tcg] Add generic translation framework
      target: [tcg] Redefine DISAS_* onto the generic translation framework (DJ_*)
      target: [tcg,i386] Port to generic translation framework
      target: [tcg,arm] Port to generic translation framework


 include/exec/exec-all.h               |   13 -
 include/exec/gen-icount.h             |    2 
 include/exec/translate-all_template.h |   73 +++
 include/qemu/queue.h                  |   12 +
 include/qom/cpu.h                     |   22 +
 target/alpha/translate.c              |   11 -
 target/arm/translate-a64.c            |  346 ++++++++--------
 target/arm/translate.c                |  720 +++++++++++++++++----------------
 target/arm/translate.h                |   45 +-
 target/cris/translate.c               |   20 -
 target/i386/translate.c               |  305 ++++++--------
 target/lm32/translate.c               |   22 +
 target/m68k/translate.c               |   18 -
 target/microblaze/translate.c         |   22 +
 target/mips/translate.c               |   15 -
 target/moxie/translate.c              |   14 -
 target/openrisc/translate.c           |   19 -
 target/ppc/translate.c                |   15 -
 target/s390x/translate.c              |   16 -
 target/sh4/translate.c                |   15 -
 target/sparc/translate.c              |   11 -
 target/tilegx/translate.c             |    7 
 target/tricore/translate.c            |    9 
 target/unicore32/translate.c          |   20 -
 target/xtensa/translate.c             |   13 -
 translate-all.c                       |    2 
 translate-all_template.h              |  204 +++++++++
 27 files changed, 1141 insertions(+), 850 deletions(-)
 create mode 100644 include/exec/translate-all_template.h
 create mode 100644 translate-all_template.h


To: qemu-devel@nongnu.org
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Crosthwaite <crosthwaite.peter@gmail.com>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Alex Bennée <alex.bennee@linaro.org>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code()
  2017-06-12 14:53 [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic translation framework Lluís Vilanova
@ 2017-06-12 14:53 ` Lluís Vilanova
  2017-06-13  1:40   ` David Gibson
                     ` (3 more replies)
  2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 2/6] queue: Add macro for incremental traversal Lluís Vilanova
                   ` (4 subsequent siblings)
  5 siblings, 4 replies; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-12 14:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alex Bennée, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, Edgar E. Iglesias, Eduardo Habkost,
	Michael Walle, Laurent Vivier, Aurelien Jarno, Yongbok Kim,
	Anthony Green, Stafford Horne, David Gibson, Alexander Graf,
	Mark Cave-Ayland, Artyom Tarasenko, Bastian Koppelmann,
	Guan Xuetao, Max Filippov, open list:ARM, open list:PowerPC

Needed to implement a target-agnostic gen_intermediate_code() in the
future.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 include/exec/exec-all.h       |    2 +-
 target/alpha/translate.c      |   11 +++++------
 target/arm/translate.c        |   20 ++++++++++----------
 target/cris/translate.c       |   17 ++++++++---------
 target/i386/translate.c       |   13 ++++++-------
 target/lm32/translate.c       |   22 +++++++++++-----------
 target/m68k/translate.c       |   15 +++++++--------
 target/microblaze/translate.c |   22 +++++++++++-----------
 target/mips/translate.c       |   15 +++++++--------
 target/moxie/translate.c      |   14 +++++++-------
 target/openrisc/translate.c   |   19 ++++++++++---------
 target/ppc/translate.c        |   15 +++++++--------
 target/s390x/translate.c      |   13 ++++++-------
 target/sh4/translate.c        |   15 +++++++--------
 target/sparc/translate.c      |   11 +++++------
 target/tilegx/translate.c     |    7 +++----
 target/tricore/translate.c    |    9 ++++-----
 target/unicore32/translate.c  |   17 ++++++++---------
 target/xtensa/translate.c     |   13 ++++++-------
 translate-all.c               |    2 +-
 20 files changed, 130 insertions(+), 142 deletions(-)

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 87ae10bcc9..1ec7637170 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -43,7 +43,7 @@ typedef ram_addr_t tb_page_addr_t;
 
 #include "qemu/log.h"
 
-void gen_intermediate_code(CPUArchState *env, struct TranslationBlock *tb);
+void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
 void restore_state_to_opc(CPUArchState *env, struct TranslationBlock *tb,
                           target_ulong *data);
 
diff --git a/target/alpha/translate.c b/target/alpha/translate.c
index 7c45ae360c..9b60680454 100644
--- a/target/alpha/translate.c
+++ b/target/alpha/translate.c
@@ -2900,10 +2900,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
     return ret;
 }
 
-void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
 {
-    AlphaCPU *cpu = alpha_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUAlphaState *env = cpu->env_ptr;
     DisasContext ctx, *ctxp = &ctx;
     target_ulong pc_start;
     target_ulong pc_mask;
@@ -2918,7 +2917,7 @@ void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
     ctx.pc = pc_start;
     ctx.mem_idx = cpu_mmu_index(env, false);
     ctx.implver = env->implver;
-    ctx.singlestep_enabled = cs->singlestep_enabled;
+    ctx.singlestep_enabled = cpu->singlestep_enabled;
 
 #ifdef CONFIG_USER_ONLY
     ctx.ir = cpu_std_ir;
@@ -2961,7 +2960,7 @@ void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
         tcg_gen_insn_start(ctx.pc);
         num_insns++;
 
-        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, ctx.pc, BP_ANY))) {
             ret = gen_excp(&ctx, EXCP_DEBUG, 0);
             /* The address covered by the breakpoint must be included in
                [tb->pc, tb->pc + tb->size) in order to for it to be
@@ -3030,7 +3029,7 @@ void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
         && qemu_log_in_addr_range(pc_start)) {
         qemu_log_lock();
         qemu_log("IN: %s\n", lookup_symbol(pc_start));
-        log_target_disas(cs, pc_start, ctx.pc - pc_start, 1);
+        log_target_disas(cpu, pc_start, ctx.pc - pc_start, 1);
         qemu_log("\n");
         qemu_log_unlock();
     }
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 0862f9e4aa..96272a9888 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -11787,10 +11787,10 @@ static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
 {
-    ARMCPU *cpu = arm_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUARMState *env = cpu->env_ptr;
+    ARMCPU *arm_cpu = arm_env_get_cpu(env);
     DisasContext dc1, *dc = &dc1;
     target_ulong pc_start;
     target_ulong next_page_start;
@@ -11804,7 +11804,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
      * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
      */
     if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
-        gen_intermediate_code_a64(cpu, tb);
+        gen_intermediate_code_a64(arm_cpu, tb);
         return;
     }
 
@@ -11814,7 +11814,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
 
     dc->is_jmp = DISAS_NEXT;
     dc->pc = pc_start;
-    dc->singlestep_enabled = cs->singlestep_enabled;
+    dc->singlestep_enabled = cpu->singlestep_enabled;
     dc->condjmp = 0;
 
     dc->aarch64 = 0;
@@ -11840,7 +11840,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
     dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
     dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(tb->flags);
     dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(tb->flags);
-    dc->cp_regs = cpu->cp_regs;
+    dc->cp_regs = arm_cpu->cp_regs;
     dc->features = env->features;
 
     /* Single step state. The code-generation logic here is:
@@ -11941,9 +11941,9 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
         }
 #endif
 
-        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+        if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
             CPUBreakpoint *bp;
-            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
+            QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
                 if (bp->pc == dc->pc) {
                     if (bp->flags & BP_CPU) {
                         gen_set_condexec(dc);
@@ -12042,7 +12042,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
         if (dc->condjmp) {
             /* FIXME:  This can theoretically happen with self-modifying
                code.  */
-            cpu_abort(cs, "IO on conditional branch instruction");
+            cpu_abort(cpu, "IO on conditional branch instruction");
         }
         gen_io_end();
     }
@@ -12156,7 +12156,7 @@ done_generating:
         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,
+        log_target_disas(cpu, pc_start, dc->pc - pc_start,
                          dc->thumb | (dc->sctlr_b << 1));
         qemu_log("\n");
         qemu_log_unlock();
diff --git a/target/cris/translate.c b/target/cris/translate.c
index 0ee05ca02d..35931e7061 100644
--- a/target/cris/translate.c
+++ b/target/cris/translate.c
@@ -3080,10 +3080,9 @@ static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc)
  */
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
 {
-    CRISCPU *cpu = cris_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUCRISState *env = cpu->env_ptr;
     uint32_t pc_start;
     unsigned int insn_len;
     struct DisasContext ctx;
@@ -3105,13 +3104,13 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
      * delayslot, like in real hw.
      */
     pc_start = tb->pc & ~1;
-    dc->cpu = cpu;
+    dc->cpu = cris_env_get_cpu(env);
     dc->tb = tb;
 
     dc->is_jmp = DISAS_NEXT;
     dc->ppc = pc_start;
     dc->pc = pc_start;
-    dc->singlestep_enabled = cs->singlestep_enabled;
+    dc->singlestep_enabled = cpu->singlestep_enabled;
     dc->flags_uptodate = 1;
     dc->flagx_known = 1;
     dc->flags_x = tb->flags & X_FLAG;
@@ -3151,7 +3150,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
                            ? dc->ppc | 1 : dc->pc);
         num_insns++;
 
-        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
             cris_evaluate_flags(dc);
             tcg_gen_movi_tl(env_pc, dc->pc);
             t_gen_raise_exception(EXCP_DEBUG);
@@ -3225,7 +3224,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
 
         /* If we are rexecuting a branch due to exceptions on
            delay slots don't break.  */
-        if (!(tb->pc & 1) && cs->singlestep_enabled) {
+        if (!(tb->pc & 1) && cpu->singlestep_enabled) {
             break;
         }
     } while (!dc->is_jmp && !dc->cpustate_changed
@@ -3258,7 +3257,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
 
     cris_evaluate_flags(dc);
 
-    if (unlikely(cs->singlestep_enabled)) {
+    if (unlikely(cpu->singlestep_enabled)) {
         if (dc->is_jmp == DISAS_NEXT) {
             tcg_gen_movi_tl(env_pc, npc);
         }
@@ -3293,7 +3292,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
         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,
+        log_target_disas(cpu, pc_start, dc->pc - pc_start,
                          env->pregs[PR_VR]);
         qemu_log("\nisize=%d osize=%d\n",
                  dc->pc - pc_start, tcg_op_buf_count());
diff --git a/target/i386/translate.c b/target/i386/translate.c
index 674ec96d5a..b38bcabfc2 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -8366,10 +8366,9 @@ void tcg_x86_init(void)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
 {
-    X86CPU *cpu = x86_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUX86State *env = cpu->env_ptr;
     DisasContext dc1, *dc = &dc1;
     target_ulong pc_ptr;
     uint32_t flags;
@@ -8392,7 +8391,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
     dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
     dc->iopl = (flags >> IOPL_SHIFT) & 3;
     dc->tf = (flags >> TF_SHIFT) & 1;
-    dc->singlestep_enabled = cs->singlestep_enabled;
+    dc->singlestep_enabled = cpu->singlestep_enabled;
     dc->cc_op = CC_OP_DYNAMIC;
     dc->cc_op_dirty = false;
     dc->cs_base = cs_base;
@@ -8414,7 +8413,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
     dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
 #endif
     dc->flags = flags;
-    dc->jmp_opt = !(dc->tf || cs->singlestep_enabled ||
+    dc->jmp_opt = !(dc->tf || cpu->singlestep_enabled ||
                     (flags & HF_INHIBIT_IRQ_MASK));
     /* Do not optimize repz jumps at all in icount mode, because
        rep movsS instructions are execured with different paths
@@ -8463,7 +8462,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
         num_insns++;
 
         /* If RF is set, suppress an internally generated breakpoint.  */
-        if (unlikely(cpu_breakpoint_test(cs, pc_ptr,
+        if (unlikely(cpu_breakpoint_test(cpu, pc_ptr,
                                          tb->flags & HF_RF_MASK
                                          ? BP_GDB : BP_ANY))) {
             gen_debug(dc, pc_ptr - dc->cs_base);
@@ -8539,7 +8538,7 @@ done_generating:
         else
 #endif
             disas_flags = !dc->code32;
-        log_target_disas(cs, pc_start, pc_ptr - pc_start, disas_flags);
+        log_target_disas(cpu, pc_start, pc_ptr - pc_start, disas_flags);
         qemu_log("\n");
         qemu_log_unlock();
     }
diff --git a/target/lm32/translate.c b/target/lm32/translate.c
index 692882f447..0ac34fc620 100644
--- a/target/lm32/translate.c
+++ b/target/lm32/translate.c
@@ -1044,10 +1044,10 @@ static inline void decode(DisasContext *dc, uint32_t ir)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
 {
-    LM32CPU *cpu = lm32_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPULM32State *env = cpu->env_ptr;
+    LM32CPU *lm32_cpu = lm32_env_get_cpu(env);
     struct DisasContext ctx, *dc = &ctx;
     uint32_t pc_start;
     uint32_t next_page_start;
@@ -1055,14 +1055,14 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
     int max_insns;
 
     pc_start = tb->pc;
-    dc->features = cpu->features;
-    dc->num_breakpoints = cpu->num_breakpoints;
-    dc->num_watchpoints = cpu->num_watchpoints;
+    dc->features = lm32_cpu->features;
+    dc->num_breakpoints = lm32_cpu->num_breakpoints;
+    dc->num_watchpoints = lm32_cpu->num_watchpoints;
     dc->tb = tb;
 
     dc->is_jmp = DISAS_NEXT;
     dc->pc = pc_start;
-    dc->singlestep_enabled = cs->singlestep_enabled;
+    dc->singlestep_enabled = cpu->singlestep_enabled;
 
     if (pc_start & 3) {
         qemu_log_mask(LOG_GUEST_ERROR,
@@ -1085,7 +1085,7 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
         tcg_gen_insn_start(dc->pc);
         num_insns++;
 
-        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
             tcg_gen_movi_tl(cpu_pc, dc->pc);
             t_gen_raise_exception(dc, EXCP_DEBUG);
             dc->is_jmp = DISAS_UPDATE;
@@ -1108,7 +1108,7 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
         dc->pc += 4;
     } while (!dc->is_jmp
          && !tcg_op_buf_full()
-         && !cs->singlestep_enabled
+         && !cpu->singlestep_enabled
          && !singlestep
          && (dc->pc < next_page_start)
          && num_insns < max_insns);
@@ -1117,7 +1117,7 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
         gen_io_end();
     }
 
-    if (unlikely(cs->singlestep_enabled)) {
+    if (unlikely(cpu->singlestep_enabled)) {
         if (dc->is_jmp == DISAS_NEXT) {
             tcg_gen_movi_tl(cpu_pc, dc->pc);
         }
@@ -1150,7 +1150,7 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
         && qemu_log_in_addr_range(pc_start)) {
         qemu_log_lock();
         qemu_log("\n");
-        log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
+        log_target_disas(cpu, pc_start, dc->pc - pc_start, 0);
         qemu_log("\nisize=%d osize=%d\n",
                  dc->pc - pc_start, tcg_op_buf_count());
         qemu_log_unlock();
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index ad4d4efb8d..0a3372818c 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5039,10 +5039,9 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
 {
-    M68kCPU *cpu = m68k_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUM68KState *env = cpu->env_ptr;
     DisasContext dc1, *dc = &dc1;
     target_ulong pc_start;
     int pc_offset;
@@ -5059,7 +5058,7 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
     dc->pc = pc_start;
     dc->cc_op = CC_OP_DYNAMIC;
     dc->cc_op_synced = 1;
-    dc->singlestep_enabled = cs->singlestep_enabled;
+    dc->singlestep_enabled = cpu->singlestep_enabled;
     dc->fpcr = env->fpcr;
     dc->user = (env->sr & SR_S) == 0;
     dc->done_mac = 0;
@@ -5080,7 +5079,7 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
         tcg_gen_insn_start(dc->pc, dc->cc_op);
         num_insns++;
 
-        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
             gen_exception(dc, dc->pc, EXCP_DEBUG);
             dc->is_jmp = DISAS_JUMP;
             /* The address covered by the breakpoint must be included in
@@ -5098,14 +5097,14 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
         dc->insn_pc = dc->pc;
 	disas_m68k_insn(env, dc);
     } while (!dc->is_jmp && !tcg_op_buf_full() &&
-             !cs->singlestep_enabled &&
+             !cpu->singlestep_enabled &&
              !singlestep &&
              (pc_offset) < (TARGET_PAGE_SIZE - 32) &&
              num_insns < max_insns);
 
     if (tb->cflags & CF_LAST_IO)
         gen_io_end();
-    if (unlikely(cs->singlestep_enabled)) {
+    if (unlikely(cpu->singlestep_enabled)) {
         /* Make sure the pc is updated, and raise a debug exception.  */
         if (!dc->is_jmp) {
             update_cc_op(dc);
@@ -5138,7 +5137,7 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
         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, 0);
+        log_target_disas(cpu, pc_start, dc->pc - pc_start, 0);
         qemu_log("\n");
         qemu_log_unlock();
     }
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
index 0bb609513c..d5f499658d 100644
--- a/target/microblaze/translate.c
+++ b/target/microblaze/translate.c
@@ -1594,10 +1594,10 @@ static inline void decode(DisasContext *dc, uint32_t ir)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
 {
-    MicroBlazeCPU *cpu = mb_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUMBState *env = cpu->env_ptr;
+    MicroBlazeCPU *mb_cpu = mb_env_get_cpu(env);
     uint32_t pc_start;
     struct DisasContext ctx;
     struct DisasContext *dc = &ctx;
@@ -1607,7 +1607,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
     int max_insns;
 
     pc_start = tb->pc;
-    dc->cpu = cpu;
+    dc->cpu = mb_cpu;
     dc->tb = tb;
     org_flags = dc->synced_flags = dc->tb_flags = tb->flags;
 
@@ -1618,13 +1618,13 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
         dc->jmp = JMP_INDIRECT;
     }
     dc->pc = pc_start;
-    dc->singlestep_enabled = cs->singlestep_enabled;
+    dc->singlestep_enabled = cpu->singlestep_enabled;
     dc->cpustate_changed = 0;
     dc->abort_at_next_insn = 0;
     dc->nr_nops = 0;
 
     if (pc_start & 3) {
-        cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start);
+        cpu_abort(cpu, "Microblaze: unaligned PC=%x\n", pc_start);
     }
 
     next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
@@ -1650,7 +1650,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
         }
 #endif
 
-        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
             t_gen_raise_exception(dc, EXCP_DEBUG);
             dc->is_jmp = DISAS_UPDATE;
             /* The address covered by the breakpoint must be included in
@@ -1707,7 +1707,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
                 break;
             }
         }
-        if (cs->singlestep_enabled) {
+        if (cpu->singlestep_enabled) {
             break;
         }
     } while (!dc->is_jmp && !dc->cpustate_changed
@@ -1728,7 +1728,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
 
     if (tb->cflags & CF_LAST_IO)
         gen_io_end();
-    /* Force an update if the per-tb cpu state has changed.  */
+    /* Force an update if the per-tb mb_cpu state has changed.  */
     if (dc->is_jmp == DISAS_NEXT
         && (dc->cpustate_changed || org_flags != dc->tb_flags)) {
         dc->is_jmp = DISAS_UPDATE;
@@ -1736,7 +1736,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
     }
     t_sync_flags(dc);
 
-    if (unlikely(cs->singlestep_enabled)) {
+    if (unlikely(cpu->singlestep_enabled)) {
         TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
 
         if (dc->is_jmp != DISAS_JUMP) {
@@ -1773,7 +1773,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
         qemu_log_lock();
         qemu_log("--------------\n");
 #if DISAS_GNU
-        log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
+        log_target_disas(cpu, pc_start, dc->pc - pc_start, 0);
 #endif
         qemu_log("\nisize=%d osize=%d\n",
                  dc->pc - pc_start, tcg_op_buf_count());
diff --git a/target/mips/translate.c b/target/mips/translate.c
index 559f8fed89..1f9e02f426 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -19878,10 +19878,9 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
     }
 }
 
-void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
 {
-    MIPSCPU *cpu = mips_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUMIPSState *env = cpu->env_ptr;
     DisasContext ctx;
     target_ulong pc_start;
     target_ulong next_page_start;
@@ -19894,7 +19893,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
     next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
     ctx.pc = pc_start;
     ctx.saved_pc = -1;
-    ctx.singlestep_enabled = cs->singlestep_enabled;
+    ctx.singlestep_enabled = cpu->singlestep_enabled;
     ctx.insn_flags = env->insn_flags;
     ctx.CP0_Config1 = env->CP0_Config1;
     ctx.tb = tb;
@@ -19941,7 +19940,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
         tcg_gen_insn_start(ctx.pc, ctx.hflags & MIPS_HFLAG_BMASK, ctx.btarget);
         num_insns++;
 
-        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, ctx.pc, BP_ANY))) {
             save_cpu_state(&ctx, 1);
             ctx.bstate = BS_BRANCH;
             gen_helper_raise_exception_debug(cpu_env);
@@ -19996,7 +19995,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
            This is what GDB expects and is consistent with what the
            hardware does (e.g. if a delay slot instruction faults, the
            reported PC is the PC of the branch).  */
-        if (cs->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0) {
+        if (cpu->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0) {
             break;
         }
 
@@ -20017,7 +20016,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
     if (tb->cflags & CF_LAST_IO) {
         gen_io_end();
     }
-    if (cs->singlestep_enabled && ctx.bstate != BS_BRANCH) {
+    if (cpu->singlestep_enabled && ctx.bstate != BS_BRANCH) {
         save_cpu_state(&ctx, ctx.bstate != BS_EXCP);
         gen_helper_raise_exception_debug(cpu_env);
     } else {
@@ -20049,7 +20048,7 @@ done_generating:
         && qemu_log_in_addr_range(pc_start)) {
         qemu_log_lock();
         qemu_log("IN: %s\n", lookup_symbol(pc_start));
-        log_target_disas(cs, pc_start, ctx.pc - pc_start, 0);
+        log_target_disas(cpu, pc_start, ctx.pc - pc_start, 0);
         qemu_log("\n");
         qemu_log_unlock();
     }
diff --git a/target/moxie/translate.c b/target/moxie/translate.c
index 0660b44c08..176063a1de 100644
--- a/target/moxie/translate.c
+++ b/target/moxie/translate.c
@@ -822,10 +822,10 @@ static int decode_opc(MoxieCPU *cpu, DisasContext *ctx)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
 {
-    MoxieCPU *cpu = moxie_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUMoxieState *env = cpu->env_ptr;
+    MoxieCPU *moxie_cpu = moxie_env_get_cpu(env);
     DisasContext ctx;
     target_ulong pc_start;
     int num_insns, max_insns;
@@ -851,7 +851,7 @@ void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
         tcg_gen_insn_start(ctx.pc);
         num_insns++;
 
-        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, ctx.pc, BP_ANY))) {
             tcg_gen_movi_i32(cpu_pc, ctx.pc);
             gen_helper_debug(cpu_env);
             ctx.bstate = BS_EXCP;
@@ -864,12 +864,12 @@ void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
         }
 
         ctx.opcode = cpu_lduw_code(env, ctx.pc);
-        ctx.pc += decode_opc(cpu, &ctx);
+        ctx.pc += decode_opc(moxie_cpu, &ctx);
 
         if (num_insns >= max_insns) {
             break;
         }
-        if (cs->singlestep_enabled) {
+        if (cpu->singlestep_enabled) {
             break;
         }
         if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) {
@@ -877,7 +877,7 @@ void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
         }
     } while (ctx.bstate == BS_NONE && !tcg_op_buf_full());
 
-    if (cs->singlestep_enabled) {
+    if (cpu->singlestep_enabled) {
         tcg_gen_movi_tl(cpu_pc, ctx.pc);
         gen_helper_debug(cpu_env);
     } else {
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index e49518e893..aaac359d5b 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -1518,9 +1518,10 @@ static void disas_openrisc_insn(DisasContext *dc, OpenRISCCPU *cpu)
     }
 }
 
-void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
 {
-    OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
+    OpenRISCState *env = cpu->env_ptr;
+    OpenRISCCPU *or_cpu = openrisc_env_get_cpu(env);
     CPUState *cs = CPU(cpu);
     struct DisasContext ctx, *dc = &ctx;
     uint32_t pc_start;
@@ -1533,10 +1534,10 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
 
     dc->is_jmp = DISAS_NEXT;
     dc->pc = pc_start;
-    dc->mem_idx = cpu_mmu_index(&cpu->env, false);
+    dc->mem_idx = cpu_mmu_index(&or_cpu->env, false);
     dc->tb_flags = tb->flags;
     dc->delayed_branch = (dc->tb_flags & TB_FLAGS_DFLAG) != 0;
-    dc->singlestep_enabled = cs->singlestep_enabled;
+    dc->singlestep_enabled = cpu->singlestep_enabled;
 
     next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
     num_insns = 0;
@@ -1571,7 +1572,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
 			   | (num_insns ? 2 : 0));
         num_insns++;
 
-        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
             tcg_gen_movi_tl(cpu_pc, dc->pc);
             gen_exception(dc, EXCP_DEBUG);
             dc->is_jmp = DISAS_UPDATE;
@@ -1586,7 +1587,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
         if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
             gen_io_start();
         }
-        disas_openrisc_insn(dc, cpu);
+        disas_openrisc_insn(dc, or_cpu);
         dc->pc = dc->pc + 4;
 
         /* delay slot */
@@ -1601,7 +1602,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
         }
     } while (!dc->is_jmp
              && !tcg_op_buf_full()
-             && !cs->singlestep_enabled
+             && !cpu->singlestep_enabled
              && !singlestep
              && (dc->pc < next_page_start)
              && num_insns < max_insns);
@@ -1619,7 +1620,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
         dc->is_jmp = DISAS_UPDATE;
         tcg_gen_movi_tl(cpu_pc, dc->pc);
     }
-    if (unlikely(cs->singlestep_enabled)) {
+    if (unlikely(cpu->singlestep_enabled)) {
         gen_exception(dc, EXCP_DEBUG);
     } else {
         switch (dc->is_jmp) {
@@ -1647,7 +1648,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
 
     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
         && qemu_log_in_addr_range(pc_start)) {
-        log_target_disas(cs, pc_start, tb->size, 0);
+        log_target_disas(cpu, pc_start, tb->size, 0);
         qemu_log("\n");
         qemu_log_unlock();
     }
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index c0cd64d927..9a934117d8 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -7203,10 +7203,9 @@ void ppc_cpu_dump_statistics(CPUState *cs, FILE*f,
 }
 
 /*****************************************************************************/
-void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
 {
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = cpu->env_ptr;
     DisasContext ctx, *ctxp = &ctx;
     opc_handler_t **table, *handler;
     target_ulong pc_start;
@@ -7267,7 +7266,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
         ctx.singlestep_enabled = 0;
     if ((env->flags & POWERPC_FLAG_BE) && msr_be)
         ctx.singlestep_enabled |= CPU_BRANCH_STEP;
-    if (unlikely(cs->singlestep_enabled)) {
+    if (unlikely(cpu->singlestep_enabled)) {
         ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP;
     }
 #if defined (DO_SINGLE_STEP) && 0
@@ -7290,7 +7289,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
         tcg_gen_insn_start(ctx.nip);
         num_insns++;
 
-        if (unlikely(cpu_breakpoint_test(cs, ctx.nip, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, ctx.nip, BP_ANY))) {
             gen_debug_exception(ctxp);
             /* The address covered by the breakpoint must be included in
                [tb->pc, tb->pc + tb->size) in order to for it to be
@@ -7369,7 +7368,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
                      ctx.exception != POWERPC_EXCP_BRANCH)) {
             gen_exception_nip(ctxp, POWERPC_EXCP_TRACE, ctx.nip);
         } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
-                            (cs->singlestep_enabled) ||
+                            (cpu->singlestep_enabled) ||
                             singlestep ||
                             num_insns >= max_insns)) {
             /* if we reach a page boundary or are single stepping, stop
@@ -7389,7 +7388,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
     if (ctx.exception == POWERPC_EXCP_NONE) {
         gen_goto_tb(&ctx, 0, ctx.nip);
     } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
-        if (unlikely(cs->singlestep_enabled)) {
+        if (unlikely(cpu->singlestep_enabled)) {
             gen_debug_exception(ctxp);
         }
         /* Generate the return instruction */
@@ -7408,7 +7407,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
         flags |= ctx.le_mode << 16;
         qemu_log_lock();
         qemu_log("IN: %s\n", lookup_symbol(pc_start));
-        log_target_disas(cs, pc_start, ctx.nip - pc_start, flags);
+        log_target_disas(cpu, pc_start, ctx.nip - pc_start, flags);
         qemu_log("\n");
         qemu_log_unlock();
     }
diff --git a/target/s390x/translate.c b/target/s390x/translate.c
index 95f91d4f08..2a17b3d7aa 100644
--- a/target/s390x/translate.c
+++ b/target/s390x/translate.c
@@ -5714,10 +5714,9 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s)
     return ret;
 }
 
-void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
 {
-    S390CPU *cpu = s390_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUS390XState *env = cpu->env_ptr;
     DisasContext dc;
     target_ulong pc_start;
     uint64_t next_page_start;
@@ -5736,7 +5735,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
     dc.pc = pc_start;
     dc.cc_op = CC_OP_DYNAMIC;
     dc.ex_value = tb->cs_base;
-    do_debug = dc.singlestep_enabled = cs->singlestep_enabled;
+    do_debug = dc.singlestep_enabled = cpu->singlestep_enabled;
 
     next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
 
@@ -5755,7 +5754,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
         tcg_gen_insn_start(dc.pc, dc.cc_op);
         num_insns++;
 
-        if (unlikely(cpu_breakpoint_test(cs, dc.pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, dc.pc, BP_ANY))) {
             status = EXIT_PC_STALE;
             do_debug = true;
             /* The address covered by the breakpoint must be included in
@@ -5779,7 +5778,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
                 || tcg_op_buf_full()
                 || num_insns >= max_insns
                 || singlestep
-                || cs->singlestep_enabled
+                || cpu->singlestep_enabled
                 || dc.ex_value)) {
             status = EXIT_PC_STALE;
         }
@@ -5829,7 +5828,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
             qemu_log("IN: EXECUTE %016" PRIx64 "\n", dc.ex_value);
         } else {
             qemu_log("IN: %s\n", lookup_symbol(pc_start));
-            log_target_disas(cs, pc_start, dc.pc - pc_start, 1);
+            log_target_disas(cpu, pc_start, dc.pc - pc_start, 1);
             qemu_log("\n");
         }
         qemu_log_unlock();
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index 8bc132b27b..6a797072d4 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -1815,10 +1815,9 @@ static void decode_opc(DisasContext * ctx)
     }
 }
 
-void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
 {
-    SuperHCPU *cpu = sh_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUSH4State *env = cpu->env_ptr;
     DisasContext ctx;
     target_ulong pc_start;
     int num_insns;
@@ -1834,7 +1833,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
        so assume it is a dynamic branch.  */
     ctx.delayed_pc = -1; /* use delayed pc from env pointer */
     ctx.tb = tb;
-    ctx.singlestep_enabled = cs->singlestep_enabled;
+    ctx.singlestep_enabled = cpu->singlestep_enabled;
     ctx.features = env->features;
     ctx.has_movcal = (ctx.tbflags & TB_FLAG_PENDING_MOVCA);
 
@@ -1852,7 +1851,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
         tcg_gen_insn_start(ctx.pc, ctx.envflags);
         num_insns++;
 
-        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, ctx.pc, BP_ANY))) {
             /* We have hit a breakpoint - make sure PC is up-to-date */
             gen_save_cpu_state(&ctx, true);
             gen_helper_debug(cpu_env);
@@ -1874,7 +1873,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
 	ctx.pc += 2;
 	if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
 	    break;
-        if (cs->singlestep_enabled) {
+        if (cpu->singlestep_enabled) {
 	    break;
         }
         if (num_insns >= max_insns)
@@ -1884,7 +1883,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
     }
     if (tb->cflags & CF_LAST_IO)
         gen_io_end();
-    if (cs->singlestep_enabled) {
+    if (cpu->singlestep_enabled) {
         gen_save_cpu_state(&ctx, true);
         gen_helper_debug(cpu_env);
     } else {
@@ -1915,7 +1914,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
         && qemu_log_in_addr_range(pc_start)) {
         qemu_log_lock();
 	qemu_log("IN:\n");	/* , lookup_symbol(pc_start)); */
-        log_target_disas(cs, pc_start, ctx.pc - pc_start, 0);
+        log_target_disas(cpu, pc_start, ctx.pc - pc_start, 0);
 	qemu_log("\n");
         qemu_log_unlock();
     }
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index aa6734d54e..90c43e4460 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -5747,10 +5747,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
     }
 }
 
-void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
+void gen_intermediate_code(CPUState *cpu, TranslationBlock * tb)
 {
-    SPARCCPU *cpu = sparc_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUSPARCState *env = cpu->env_ptr;
     target_ulong pc_start, last_pc;
     DisasContext dc1, *dc = &dc1;
     int num_insns;
@@ -5768,7 +5767,7 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
     dc->def = env->def;
     dc->fpu_enabled = tb_fpu_enabled(tb->flags);
     dc->address_mask_32bit = tb_am_enabled(tb->flags);
-    dc->singlestep = (cs->singlestep_enabled || singlestep);
+    dc->singlestep = (cpu->singlestep_enabled || singlestep);
 #ifndef CONFIG_USER_ONLY
     dc->supervisor = (tb->flags & TB_FLAG_SUPER) != 0;
 #endif
@@ -5800,7 +5799,7 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
         num_insns++;
         last_pc = dc->pc;
 
-        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
             if (dc->pc != pc_start) {
                 save_state(dc);
             }
@@ -5864,7 +5863,7 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
         qemu_log_lock();
         qemu_log("--------------\n");
         qemu_log("IN: %s\n", lookup_symbol(pc_start));
-        log_target_disas(cs, pc_start, last_pc + 4 - pc_start, 0);
+        log_target_disas(cpu, pc_start, last_pc + 4 - pc_start, 0);
         qemu_log("\n");
         qemu_log_unlock();
     }
diff --git a/target/tilegx/translate.c b/target/tilegx/translate.c
index ff2ef7b63d..a86e9e9d22 100644
--- a/target/tilegx/translate.c
+++ b/target/tilegx/translate.c
@@ -2370,12 +2370,11 @@ static void translate_one_bundle(DisasContext *dc, uint64_t bundle)
     }
 }
 
-void gen_intermediate_code(CPUTLGState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
 {
-    TileGXCPU *cpu = tilegx_env_get_cpu(env);
+    CPUTLGState *env = cpu->env_ptr;
     DisasContext ctx;
     DisasContext *dc = &ctx;
-    CPUState *cs = CPU(cpu);
     uint64_t pc_start = tb->pc;
     uint64_t next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
     int num_insns = 0;
@@ -2397,7 +2396,7 @@ void gen_intermediate_code(CPUTLGState *env, struct TranslationBlock *tb)
     if (!max_insns) {
         max_insns = CF_COUNT_MASK;
     }
-    if (cs->singlestep_enabled || singlestep) {
+    if (cpu->singlestep_enabled || singlestep) {
         max_insns = 1;
     }
     if (max_insns > TCG_MAX_INSNS) {
diff --git a/target/tricore/translate.c b/target/tricore/translate.c
index ddd2dd07dd..1930da2f2a 100644
--- a/target/tricore/translate.c
+++ b/target/tricore/translate.c
@@ -8782,10 +8782,9 @@ static void decode_opc(CPUTriCoreState *env, DisasContext *ctx, int *is_branch)
     }
 }
 
-void gen_intermediate_code(CPUTriCoreState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
 {
-    TriCoreCPU *cpu = tricore_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUTriCoreState *env = cpu->env_ptr;
     DisasContext ctx;
     target_ulong pc_start;
     int num_insns, max_insns;
@@ -8806,7 +8805,7 @@ void gen_intermediate_code(CPUTriCoreState *env, struct TranslationBlock *tb)
     ctx.pc = pc_start;
     ctx.saved_pc = -1;
     ctx.tb = tb;
-    ctx.singlestep_enabled = cs->singlestep_enabled;
+    ctx.singlestep_enabled = cpu->singlestep_enabled;
     ctx.bstate = BS_NONE;
     ctx.mem_idx = cpu_mmu_index(env, false);
 
@@ -8840,7 +8839,7 @@ void gen_intermediate_code(CPUTriCoreState *env, struct TranslationBlock *tb)
         && qemu_log_in_addr_range(pc_start)) {
         qemu_log_lock();
         qemu_log("IN: %s\n", lookup_symbol(pc_start));
-        log_target_disas(cs, pc_start, ctx.pc - pc_start, 0);
+        log_target_disas(cpu, pc_start, ctx.pc - pc_start, 0);
         qemu_log("\n");
         qemu_log_unlock();
     }
diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c
index 666a2016a8..494ed58c10 100644
--- a/target/unicore32/translate.c
+++ b/target/unicore32/translate.c
@@ -1869,10 +1869,9 @@ static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
 {
-    UniCore32CPU *cpu = uc32_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUUniCore32State *env = cpu->env_ptr;
     DisasContext dc1, *dc = &dc1;
     target_ulong pc_start;
     uint32_t next_page_start;
@@ -1888,7 +1887,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
 
     dc->is_jmp = DISAS_NEXT;
     dc->pc = pc_start;
-    dc->singlestep_enabled = cs->singlestep_enabled;
+    dc->singlestep_enabled = cpu->singlestep_enabled;
     dc->condjmp = 0;
     cpu_F0s = tcg_temp_new_i32();
     cpu_F1s = tcg_temp_new_i32();
@@ -1917,7 +1916,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
         tcg_gen_insn_start(dc->pc);
         num_insns++;
 
-        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
             gen_set_pc_im(dc->pc);
             gen_exception(EXCP_DEBUG);
             dc->is_jmp = DISAS_JUMP;
@@ -1949,7 +1948,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
          * Also stop translation when a page boundary is reached.  This
          * ensures prefetch aborts occur at the right place.  */
     } while (!dc->is_jmp && !tcg_op_buf_full() &&
-             !cs->singlestep_enabled &&
+             !cpu->singlestep_enabled &&
              !singlestep &&
              dc->pc < next_page_start &&
              num_insns < max_insns);
@@ -1958,7 +1957,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
         if (dc->condjmp) {
             /* FIXME:  This can theoretically happen with self-modifying
                code.  */
-            cpu_abort(cs, "IO on conditional branch instruction");
+            cpu_abort(cpu, "IO on conditional branch instruction");
         }
         gen_io_end();
     }
@@ -1966,7 +1965,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
     /* At this stage dc->condjmp will only be set when the skipped
        instruction was a conditional branch or trap, and the PC has
        already been written.  */
-    if (unlikely(cs->singlestep_enabled)) {
+    if (unlikely(cpu->singlestep_enabled)) {
         /* Make sure the pc is updated, and raise a debug exception.  */
         if (dc->condjmp) {
             if (dc->is_jmp == DISAS_SYSCALL) {
@@ -2027,7 +2026,7 @@ done_generating:
         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, 0);
+        log_target_disas(cpu, pc_start, dc->pc - pc_start, 0);
         qemu_log("\n");
         qemu_log_unlock();
     }
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index 263002486c..63e4f25c08 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -3117,10 +3117,9 @@ static void gen_ibreak_check(CPUXtensaState *env, DisasContext *dc)
     }
 }
 
-void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
 {
-    XtensaCPU *cpu = xtensa_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUXtensaState *env = cpu->env_ptr;
     DisasContext dc;
     int insn_count = 0;
     int max_insns = tb->cflags & CF_COUNT_MASK;
@@ -3136,7 +3135,7 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
     }
 
     dc.config = env->config;
-    dc.singlestep_enabled = cs->singlestep_enabled;
+    dc.singlestep_enabled = cpu->singlestep_enabled;
     dc.tb = tb;
     dc.pc = pc_start;
     dc.ring = tb->flags & XTENSA_TBFLAG_RING_MASK;
@@ -3179,7 +3178,7 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
         tcg_gen_insn_start(dc.pc);
         ++insn_count;
 
-        if (unlikely(cpu_breakpoint_test(cs, dc.pc, BP_ANY))) {
+        if (unlikely(cpu_breakpoint_test(cpu, dc.pc, BP_ANY))) {
             tcg_gen_movi_i32(cpu_pc, dc.pc);
             gen_exception(&dc, EXCP_DEBUG);
             dc.is_jmp = DISAS_UPDATE;
@@ -3215,7 +3214,7 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
         if (dc.icount) {
             tcg_gen_mov_i32(cpu_SR[ICOUNT], dc.next_icount);
         }
-        if (cs->singlestep_enabled) {
+        if (cpu->singlestep_enabled) {
             tcg_gen_movi_i32(cpu_pc, dc.pc);
             gen_exception(&dc, EXCP_DEBUG);
             break;
@@ -3247,7 +3246,7 @@ done:
         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, 0);
+        log_target_disas(cpu, pc_start, dc.pc - pc_start, 0);
         qemu_log("\n");
         qemu_log_unlock();
     }
diff --git a/translate-all.c b/translate-all.c
index b3ee876526..e5de5cace9 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -1292,7 +1292,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
     tcg_func_start(&tcg_ctx);
 
     tcg_ctx.cpu = ENV_GET_CPU(env);
-    gen_intermediate_code(env, tb);
+    gen_intermediate_code(cpu, tb);
     tcg_ctx.cpu = NULL;
 
     trace_translate_block(tb, tb->pc, tb->tc_ptr);

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [Qemu-devel] [PATCH v6 2/6] queue: Add macro for incremental traversal
  2017-06-12 14:53 [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic translation framework Lluís Vilanova
  2017-06-12 14:53 ` [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
@ 2017-06-12 14:54 ` Lluís Vilanova
  2017-06-19 23:20   ` Richard Henderson
  2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework Lluís Vilanova
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-12 14:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alex Bennée, Richard Henderson, Peter Crosthwaite, Paolo Bonzini

Adds macro QTAILQ_FOREACH_CONTINUE to support incremental list
traversal.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 include/qemu/queue.h |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/include/qemu/queue.h b/include/qemu/queue.h
index 35292c3155..eb2bf9cb1c 100644
--- a/include/qemu/queue.h
+++ b/include/qemu/queue.h
@@ -415,6 +415,18 @@ struct {                                                                \
                 (var);                                                  \
                 (var) = ((var)->field.tqe_next))
 
+/**
+ * QTAILQ_FOREACH_CONTINUE:
+ * @var: Variable to resume iteration from.
+ * @field: Field in @var holding a QTAILQ_ENTRY for this queue.
+ *
+ * Resumes iteration on a queue from the element in @var.
+ */
+#define QTAILQ_FOREACH_CONTINUE(var, field)                             \
+        for ((var) = ((var)->field.tqe_next);                           \
+                (var);                                                  \
+                (var) = ((var)->field.tqe_next))
+
 #define QTAILQ_FOREACH_SAFE(var, head, field, next_var)                 \
         for ((var) = ((head)->tqh_first);                               \
                 (var) && ((next_var) = ((var)->field.tqe_next), 1);     \

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework
  2017-06-12 14:53 [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic translation framework Lluís Vilanova
  2017-06-12 14:53 ` [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
  2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 2/6] queue: Add macro for incremental traversal Lluís Vilanova
@ 2017-06-12 14:54 ` Lluís Vilanova
  2017-06-15 22:05   ` [Qemu-devel] [PATCH] translator mega-patch Emilio G. Cota
  2017-06-15 22:19   ` [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework Emilio G. Cota
  2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 4/6] target: [tcg] Redefine DISAS_* onto the generic translation framework (DJ_*) Lluís Vilanova
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-12 14:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alex Bennée, Richard Henderson, Peter Crosthwaite, Paolo Bonzini

Signed-off-by: Lluís Vilanova <vilanova@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 +++++++++++++++++++++++++++++++++
 4 files changed, 300 insertions(+), 1 deletion(-)
 create mode 100644 include/exec/translate-all_template.h
 create mode 100644 translate-all_template.h

diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h
index 62d462e494..547c979629 100644
--- a/include/exec/gen-icount.h
+++ b/include/exec/gen-icount.h
@@ -44,7 +44,7 @@ static inline void gen_tb_start(TranslationBlock *tb)
     tcg_temp_free_i32(count);
 }
 
-static void gen_tb_end(TranslationBlock *tb, int num_insns)
+static inline void gen_tb_end(TranslationBlock *tb, int num_insns)
 {
     if (tb->cflags & CF_USE_ICOUNT) {
         /* Update the num_insn immediate parameter now that we know
diff --git a/include/exec/translate-all_template.h b/include/exec/translate-all_template.h
new file mode 100644
index 0000000000..51c8a43b80
--- /dev/null
+++ b/include/exec/translate-all_template.h
@@ -0,0 +1,73 @@
+/*
+ * Generic intermediate code generation.
+ *
+ * Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef EXEC__TRANSLATE_ALL_TEMPLATE_H
+#define EXEC__TRANSLATE_ALL_TEMPLATE_H
+
+/*
+ * Include this header from a target-specific file, and add a
+ *
+ *     DisasContextBase base;
+ *
+ * member in your target-specific DisasContext.
+ */
+
+
+#include "exec/exec-all.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;
+
+#endif  /* EXEC__TRANSLATE_ALL_TEMPLATE_H */
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 89ddb686fb..d46e8df756 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -982,6 +982,28 @@ static inline bool cpu_breakpoint_test(CPUState *cpu, vaddr pc, int mask)
     return false;
 }
 
+/* Get first breakpoint matching a PC */
+static inline CPUBreakpoint *cpu_breakpoint_get(CPUState *cpu, vaddr pc,
+                                                CPUBreakpoint *bp)
+{
+    if (likely(bp == NULL)) {
+        if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
+                if (bp->pc == pc) {
+                    return bp;
+                }
+            }
+        }
+    } else {
+        QTAILQ_FOREACH_CONTINUE(bp, entry) {
+            if (bp->pc == pc) {
+                return bp;
+            }
+        }
+    }
+    return NULL;
+}
+
 int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
                           int flags, CPUWatchpoint **watchpoint);
 int cpu_watchpoint_remove(CPUState *cpu, vaddr addr,
diff --git a/translate-all_template.h b/translate-all_template.h
new file mode 100644
index 0000000000..3e3f0816f7
--- /dev/null
+++ b/translate-all_template.h
@@ -0,0 +1,204 @@
+/*
+ * Generic intermediate code generation.
+ *
+ * Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TRANSLATE_ALL_TEMPLATE_H
+#define TRANSLATE_ALL_TEMPLATE_H
+
+/*
+ * Include this header from a target-specific file, which must define the
+ * target-specific functions declared below.
+ *
+ * These must be paired with instructions in "exec/translate-all_template.h".
+ */
+
+
+#include "cpu.h"
+#include "qemu/error-report.h"
+
+
+static void gen_intermediate_code_target_init_disas_context(
+    DisasContext *dc, CPUArchState *env);
+
+static void gen_intermediate_code_target_init_globals(
+    DisasContext *dc, CPUArchState *env);
+
+static void gen_intermediate_code_target_tb_start(
+    DisasContext *dc, CPUArchState *env);
+
+static void gen_intermediate_code_target_insn_start(
+    DisasContext *dc, CPUArchState *env);
+
+static BreakpointHitType gen_intermediate_code_target_breakpoint_hit(
+    DisasContext *dc, CPUArchState *env,
+    const CPUBreakpoint *bp);
+
+static target_ulong gen_intermediate_code_target_disas_insn(
+    DisasContext *dc, CPUArchState *env);
+
+static DisasJumpType gen_intermediate_code_target_stop_check(
+    DisasContext *dc, CPUArchState *env);
+
+static void gen_intermediate_code_target_stop(
+    DisasContext *dc, CPUArchState *env);
+
+static int gen_intermediate_code_target_get_disas_flags(
+    const DisasContext *dc);
+
+
+static inline void gen_intermediate_code_tcg_check(const DisasContext *dc)
+{
+    if (tcg_check_temp_count()) {
+        error_report("warning: TCG temporary leaks before "TARGET_FMT_lx,
+                     dc->base.pc_next);
+    }
+}
+
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
+{
+    CPUArchState *env = cpu->env_ptr;
+    DisasContext dc1, *dc = &dc1;
+    int max_insns;
+
+    /* Initialize DisasContext */
+    dc->base.tb = tb;
+    dc->base.singlestep_enabled = cpu->singlestep_enabled;
+    dc->base.pc_first = tb->pc;
+    dc->base.pc_next = dc->base.pc_first;
+    dc->base.jmp_type = DJ_NEXT;
+    dc->base.num_insns = 0;
+    gen_intermediate_code_target_init_disas_context(dc, env);
+
+    /* Initialize globals */
+    gen_intermediate_code_target_init_globals(dc, env);
+    tcg_clear_temp_count();
+
+    /* Instruction counting */
+    max_insns = dc->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 (dc->base.singlestep_enabled || singlestep) {
+        max_insns = 1;
+    }
+
+    /* Start translating */
+    gen_tb_start(dc->base.tb);
+    gen_intermediate_code_target_tb_start(dc, env);
+
+    while (true) {
+        CPUBreakpoint *bp;
+
+        dc->base.num_insns++;
+        gen_intermediate_code_target_insn_start(dc, env);
+
+        /* Early exit before breakpoint checks */
+        if (unlikely(dc->base.jmp_type != DJ_NEXT)) {
+            break;
+        }
+
+        /* Pass breakpoint hits to target for further processing */
+        bp = NULL;
+        do {
+            bp = cpu_breakpoint_get(cpu, dc->base.pc_next, bp);
+            if (unlikely(bp)) {
+                BreakpointHitType bh =
+                    gen_intermediate_code_target_breakpoint_hit(dc, 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 (dc->base.num_insns == max_insns &&
+            (dc->base.tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+
+        /* Disassemble one instruction */
+        dc->base.pc_next = gen_intermediate_code_target_disas_insn(dc, env);
+
+        /**************************************************/
+        /* Conditions to stop translation                 */
+        /**************************************************/
+
+        /* Disassembly already set a stop condition */
+        if (dc->base.jmp_type >= DJ_TARGET) {
+            break;
+        }
+
+        /* Target-specific conditions */
+        dc->base.jmp_type = gen_intermediate_code_target_stop_check(dc, env);
+        if (dc->base.jmp_type >= DJ_TARGET) {
+            break;
+        }
+
+        /* Too many instructions */
+        if (tcg_op_buf_full() || dc->base.num_insns >= max_insns) {
+            dc->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 ((dc->base.pc_first & TARGET_PAGE_MASK)
+            != (dc->base.pc_next & TARGET_PAGE_MASK)) {
+            dc->base.jmp_type = DJ_TOO_MANY;
+            break;
+        }
+
+        gen_intermediate_code_tcg_check(dc);
+    }
+
+    gen_intermediate_code_target_stop(dc, env);
+
+    if (dc->base.tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+
+done_generating:
+    gen_tb_end(dc->base.tb, dc->base.num_insns);
+
+    gen_intermediate_code_tcg_check(dc);
+
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
+        qemu_log_in_addr_range(dc->base.pc_first)) {
+        qemu_log_lock();
+        qemu_log("----------------\n");
+        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
+        log_target_disas(cpu, dc->base.pc_first,
+                         dc->base.pc_next - dc->base.pc_first,
+                         gen_intermediate_code_target_get_disas_flags(dc));
+        qemu_log("\n");
+        qemu_log_unlock();
+    }
+#endif
+
+    dc->base.tb->size = dc->base.pc_next - dc->base.pc_first;
+    dc->base.tb->icount = dc->base.num_insns;
+}
+
+#endif  /* TRANSLATE_ALL_TEMPLATE_H */

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [Qemu-devel] [PATCH v6 4/6] target: [tcg] Redefine DISAS_* onto the generic translation framework (DJ_*)
  2017-06-12 14:53 [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (2 preceding siblings ...)
  2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework Lluís Vilanova
@ 2017-06-12 14:54 ` Lluís Vilanova
  2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 6/6] target: [tcg, arm] Port to generic translation framework Lluís Vilanova
  2017-06-15 18:02 ` [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic " Emilio G. Cota
  5 siblings, 0 replies; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-12 14:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alex Bennée, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, Edgar E. Iglesias, Laurent Vivier,
	Alexander Graf, Guan Xuetao, open list:ARM

Temporarily redefine DISAS_* values based on DJ_TARGET. They should
disappear as targets get ported to the generic framework.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 include/exec/exec-all.h      |   11 +++++++----
 target/arm/translate.h       |   19 ++++++++++---------
 target/cris/translate.c      |    3 ++-
 target/m68k/translate.c      |    3 ++-
 target/s390x/translate.c     |    3 ++-
 target/unicore32/translate.c |    3 ++-
 6 files changed, 25 insertions(+), 17 deletions(-)

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 1ec7637170..6ad31a8b6f 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -36,10 +36,13 @@ typedef ram_addr_t tb_page_addr_t;
 #endif
 
 /* is_jmp field values */
-#define DISAS_NEXT    0 /* next instruction can be analyzed */
-#define DISAS_JUMP    1 /* only pc was modified dynamically */
-#define DISAS_UPDATE  2 /* cpu state was modified dynamically */
-#define DISAS_TB_JUMP 3 /* only pc was modified statically */
+/* 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 */
+#define DISAS_TB_JUMP (DJ_TARGET + 2)   /* only pc was modified statically */
+#define DISAS_TARGET  (DJ_TARGET + 3)   /* base for target-specific values */
 
 #include "qemu/log.h"
 
diff --git a/target/arm/translate.h b/target/arm/translate.h
index 15d383d9af..e42fdbe61c 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -120,29 +120,30 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
 }
 
 /* target-specific extra values for is_jmp */
+/* TODO: rename as DJ_* when transitioning this target to generic translation */
 /* These instructions trap after executing, so the A32/T32 decoder must
  * defer them until after the conditional execution state has been updated.
  * WFI also needs special handling when single-stepping.
  */
-#define DISAS_WFI 4
-#define DISAS_SWI 5
+#define DISAS_WFI (DISAS_TARGET + 0)
+#define DISAS_SWI (DISAS_TARGET + 1)
 /* For instructions which unconditionally cause an exception we can skip
  * emitting unreachable code at the end of the TB in the A64 decoder
  */
-#define DISAS_EXC 6
+#define DISAS_EXC (DISAS_TARGET + 2)
 /* WFE */
-#define DISAS_WFE 7
-#define DISAS_HVC 8
-#define DISAS_SMC 9
-#define DISAS_YIELD 10
+#define DISAS_WFE (DISAS_TARGET + 3)
+#define DISAS_HVC (DISAS_TARGET + 4)
+#define DISAS_SMC (DISAS_TARGET + 5)
+#define DISAS_YIELD (DISAS_TARGET + 6)
 /* M profile branch which might be an exception return (and so needs
  * custom end-of-TB code)
  */
-#define DISAS_BX_EXCRET 11
+#define DISAS_BX_EXCRET (DISAS_TARGET + 7)
 /* For instructions which want an immediate exit to the main loop,
  * as opposed to attempting to use lookup_and_goto_ptr.
  */
-#define DISAS_EXIT 12
+#define DISAS_EXIT (DISAS_TARGET + 8)
 
 #ifdef TARGET_AARCH64
 void a64_translate_init(void);
diff --git a/target/cris/translate.c b/target/cris/translate.c
index 35931e7061..85916196fc 100644
--- a/target/cris/translate.c
+++ b/target/cris/translate.c
@@ -50,7 +50,8 @@
 #define BUG() (gen_BUG(dc, __FILE__, __LINE__))
 #define BUG_ON(x) ({if (x) BUG();})
 
-#define DISAS_SWI 5
+/* TODO: rename as DJ_* when transitioning this target to generic translation */
+#define DISAS_SWI (DISAS_TARGET + 0)
 
 /* Used by the decoder.  */
 #define EXTRACT_FIELD(src, start, end) \
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 0a3372818c..3a0cb6227f 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -190,7 +190,8 @@ static void do_writebacks(DisasContext *s)
     }
 }
 
-#define DISAS_JUMP_NEXT 4
+/* TODO: rename as DJ_* when transitioning this target to generic translation */
+#define DISAS_JUMP_NEXT (DISAS_TARGET + 0)
 
 #if defined(CONFIG_USER_ONLY)
 #define IS_USER(s) 1
diff --git a/target/s390x/translate.c b/target/s390x/translate.c
index 2a17b3d7aa..98365bd29c 100644
--- a/target/s390x/translate.c
+++ b/target/s390x/translate.c
@@ -76,7 +76,8 @@ typedef struct {
     } u;
 } DisasCompare;
 
-#define DISAS_EXCP 4
+/* TODO: rename as DJ_* when transitioning this target to generic translation */
+#define DISAS_EXCP (DISAS_TARGET + 0)
 
 #ifdef DEBUG_INLINE_BRANCHES
 static uint64_t inline_branch_hit[CC_OP_MAX];
diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c
index 494ed58c10..374b6bb079 100644
--- a/target/unicore32/translate.c
+++ b/target/unicore32/translate.c
@@ -45,9 +45,10 @@ typedef struct DisasContext {
 #define IS_USER(s)      1
 #endif
 
+/* TODO: rename as DJ_* when transitioning this target to generic translation */
 /* These instructions trap after executing, so defer them until after the
    conditional executions state has been updated.  */
-#define DISAS_SYSCALL 5
+#define DISAS_SYSCALL (DISAS_TARGET + 0)
 
 static TCGv_env cpu_env;
 static TCGv_i32 cpu_R[32];

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [Qemu-devel] [PATCH v6 6/6] target: [tcg, arm] Port to generic translation framework
  2017-06-12 14:53 [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (3 preceding siblings ...)
  2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 4/6] target: [tcg] Redefine DISAS_* onto the generic translation framework (DJ_*) Lluís Vilanova
@ 2017-06-12 14:54 ` Lluís Vilanova
  2017-06-16  0:18   ` Emilio G. Cota
  2017-06-15 18:02 ` [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic " Emilio G. Cota
  5 siblings, 1 reply; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-12 14:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alex Bennée, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, open list:ARM

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 target/arm/translate-a64.c |  346 ++++++++++-----------
 target/arm/translate.c     |  720 ++++++++++++++++++++++----------------------
 target/arm/translate.h     |   46 ++-
 3 files changed, 560 insertions(+), 552 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 860e279658..60264ce1c2 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -302,17 +302,17 @@ static void gen_exception(int excp, uint32_t syndrome, uint32_t target_el)
 
 static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
 {
-    gen_a64_set_pc_im(s->pc - offset);
+    gen_a64_set_pc_im(s->base.pc_next - offset);
     gen_exception_internal(excp);
-    s->is_jmp = DISAS_EXC;
+    s->base.jmp_type = DJ_EXC;
 }
 
 static void gen_exception_insn(DisasContext *s, int offset, int excp,
                                uint32_t syndrome, uint32_t target_el)
 {
-    gen_a64_set_pc_im(s->pc - offset);
+    gen_a64_set_pc_im(s->base.pc_next - offset);
     gen_exception(excp, syndrome, target_el);
-    s->is_jmp = DISAS_EXC;
+    s->base.jmp_type = DJ_EXC;
 }
 
 static void gen_ss_advance(DisasContext *s)
@@ -340,7 +340,7 @@ static void gen_step_complete_exception(DisasContext *s)
     gen_ss_advance(s);
     gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
                   default_exception_el(s));
-    s->is_jmp = DISAS_EXC;
+    s->base.jmp_type = DJ_EXC;
 }
 
 static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
@@ -348,13 +348,14 @@ static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
     /* No direct tb linking with singlestep (either QEMU's or the ARM
      * debug architecture kind) or deterministic io
      */
-    if (s->singlestep_enabled || s->ss_active || (s->tb->cflags & CF_LAST_IO)) {
+    if (s->base.singlestep_enabled || s->ss_active ||
+        (s->base.tb->cflags & CF_LAST_IO)) {
         return false;
     }
 
 #ifndef CONFIG_USER_ONLY
     /* Only link tbs from inside the same guest page */
-    if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
+    if ((s->base.tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
         return false;
     }
 #endif
@@ -366,21 +367,21 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
 {
     TranslationBlock *tb;
 
-    tb = s->tb;
+    tb = s->base.tb;
     if (use_goto_tb(s, n, dest)) {
         tcg_gen_goto_tb(n);
         gen_a64_set_pc_im(dest);
         tcg_gen_exit_tb((intptr_t)tb + n);
-        s->is_jmp = DISAS_TB_JUMP;
+        s->base.jmp_type = DJ_TB_JUMP;
     } else {
         gen_a64_set_pc_im(dest);
         if (s->ss_active) {
             gen_step_complete_exception(s);
-        } else if (s->singlestep_enabled) {
+        } else if (s->base.singlestep_enabled) {
             gen_exception_internal(EXCP_DEBUG);
         } else {
             tcg_gen_lookup_and_goto_ptr(cpu_pc);
-            s->is_jmp = DISAS_TB_JUMP;
+            s->base.jmp_type = DJ_TB_JUMP;
         }
     }
 }
@@ -397,11 +398,11 @@ static void unallocated_encoding(DisasContext *s)
         qemu_log_mask(LOG_UNIMP,                                         \
                       "%s:%d: unsupported instruction encoding 0x%08x "  \
                       "at pc=%016" PRIx64 "\n",                          \
-                      __FILE__, __LINE__, insn, s->pc - 4);              \
+                      __FILE__, __LINE__, insn, s->base.pc_next - 4);    \
         unallocated_encoding(s);                                         \
     } while (0);
 
-static void init_tmp_a64_array(DisasContext *s)
+void init_tmp_a64_array(DisasContext *s)
 {
 #ifdef CONFIG_DEBUG_TCG
     int i;
@@ -1216,11 +1217,11 @@ static inline AArch64DecodeFn *lookup_disas_fn(const AArch64DecodeTable *table,
  */
 static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
 {
-    uint64_t addr = s->pc + sextract32(insn, 0, 26) * 4 - 4;
+    uint64_t addr = s->base.pc_next + sextract32(insn, 0, 26) * 4 - 4;
 
     if (insn & (1U << 31)) {
         /* C5.6.26 BL Branch with link */
-        tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
+        tcg_gen_movi_i64(cpu_reg(s, 30), s->base.pc_next);
     }
 
     /* C5.6.20 B Branch / C5.6.26 BL Branch with link */
@@ -1243,7 +1244,7 @@ static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
     sf = extract32(insn, 31, 1);
     op = extract32(insn, 24, 1); /* 0: CBZ; 1: CBNZ */
     rt = extract32(insn, 0, 5);
-    addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
+    addr = s->base.pc_next + sextract32(insn, 5, 19) * 4 - 4;
 
     tcg_cmp = read_cpu_reg(s, rt, sf);
     label_match = gen_new_label();
@@ -1251,7 +1252,7 @@ static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
     tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
                         tcg_cmp, 0, label_match);
 
-    gen_goto_tb(s, 0, s->pc);
+    gen_goto_tb(s, 0, s->base.pc_next);
     gen_set_label(label_match);
     gen_goto_tb(s, 1, addr);
 }
@@ -1271,7 +1272,7 @@ static void disas_test_b_imm(DisasContext *s, uint32_t insn)
 
     bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5);
     op = extract32(insn, 24, 1); /* 0: TBZ; 1: TBNZ */
-    addr = s->pc + sextract32(insn, 5, 14) * 4 - 4;
+    addr = s->base.pc_next + sextract32(insn, 5, 14) * 4 - 4;
     rt = extract32(insn, 0, 5);
 
     tcg_cmp = tcg_temp_new_i64();
@@ -1280,7 +1281,7 @@ static void disas_test_b_imm(DisasContext *s, uint32_t insn)
     tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
                         tcg_cmp, 0, label_match);
     tcg_temp_free_i64(tcg_cmp);
-    gen_goto_tb(s, 0, s->pc);
+    gen_goto_tb(s, 0, s->base.pc_next);
     gen_set_label(label_match);
     gen_goto_tb(s, 1, addr);
 }
@@ -1300,14 +1301,14 @@ static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
         unallocated_encoding(s);
         return;
     }
-    addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
+    addr = s->base.pc_next + sextract32(insn, 5, 19) * 4 - 4;
     cond = extract32(insn, 0, 4);
 
     if (cond < 0x0e) {
         /* genuinely conditional branches */
         TCGLabel *label_match = gen_new_label();
         arm_gen_test_cc(cond, label_match);
-        gen_goto_tb(s, 0, s->pc);
+        gen_goto_tb(s, 0, s->base.pc_next);
         gen_set_label(label_match);
         gen_goto_tb(s, 1, addr);
     } else {
@@ -1331,16 +1332,16 @@ static void handle_hint(DisasContext *s, uint32_t insn,
     case 0: /* NOP */
         return;
     case 3: /* WFI */
-        s->is_jmp = DISAS_WFI;
+        s->base.jmp_type = DJ_WFI;
         return;
     case 1: /* YIELD */
         if (!parallel_cpus) {
-            s->is_jmp = DISAS_YIELD;
+            s->base.jmp_type = DJ_YIELD;
         }
         return;
     case 2: /* WFE */
         if (!parallel_cpus) {
-            s->is_jmp = DISAS_WFE;
+            s->base.jmp_type = DJ_WFE;
         }
         return;
     case 4: /* SEV */
@@ -1393,7 +1394,7 @@ static void handle_sync(DisasContext *s, uint32_t insn,
          * a self-modified code correctly and also to take
          * any pending interrupts immediately.
          */
-        s->is_jmp = DISAS_UPDATE;
+        s->base.jmp_type = DJ_UPDATE;
         return;
     default:
         unallocated_encoding(s);
@@ -1418,11 +1419,11 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
     {
         TCGv_i32 tcg_imm = tcg_const_i32(crm);
         TCGv_i32 tcg_op = tcg_const_i32(op);
-        gen_a64_set_pc_im(s->pc - 4);
+        gen_a64_set_pc_im(s->base.pc_next - 4);
         gen_helper_msr_i_pstate(cpu_env, tcg_op, tcg_imm);
         tcg_temp_free_i32(tcg_imm);
         tcg_temp_free_i32(tcg_op);
-        s->is_jmp = DISAS_UPDATE;
+        s->base.jmp_type = DJ_UPDATE;
         break;
     }
     default:
@@ -1518,7 +1519,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
         TCGv_i32 tcg_syn, tcg_isread;
         uint32_t syndrome;
 
-        gen_a64_set_pc_im(s->pc - 4);
+        gen_a64_set_pc_im(s->base.pc_next - 4);
         tmpptr = tcg_const_ptr(ri);
         syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
         tcg_syn = tcg_const_i32(syndrome);
@@ -1557,7 +1558,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
         break;
     }
 
-    if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
+    if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
         gen_io_start();
     }
 
@@ -1588,16 +1589,16 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
         }
     }
 
-    if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
+    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();
-        s->is_jmp = DISAS_UPDATE;
+        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,
          * but allow this to be suppressed by the register definition
          * (usually only necessary to work around guest bugs).
          */
-        s->is_jmp = DISAS_UPDATE;
+        s->base.jmp_type = DJ_UPDATE;
     }
 }
 
@@ -1677,7 +1678,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
             /* The pre HVC helper handles cases when HVC gets trapped
              * as an undefined insn by runtime configuration.
              */
-            gen_a64_set_pc_im(s->pc - 4);
+            gen_a64_set_pc_im(s->base.pc_next - 4);
             gen_helper_pre_hvc(cpu_env);
             gen_ss_advance(s);
             gen_exception_insn(s, 0, EXCP_HVC, syn_aa64_hvc(imm16), 2);
@@ -1687,7 +1688,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
                 unallocated_encoding(s);
                 break;
             }
-            gen_a64_set_pc_im(s->pc - 4);
+            gen_a64_set_pc_im(s->base.pc_next - 4);
             tmp = tcg_const_i32(syn_aa64_smc(imm16));
             gen_helper_pre_smc(cpu_env, tmp);
             tcg_temp_free_i32(tmp);
@@ -1777,7 +1778,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
         gen_a64_set_pc(s, cpu_reg(s, rn));
         /* BLR also needs to load return address */
         if (opc == 1) {
-            tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
+            tcg_gen_movi_i64(cpu_reg(s, 30), s->base.pc_next);
         }
         break;
     case 4: /* ERET */
@@ -1786,7 +1787,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
             return;
         }
         gen_helper_exception_return(cpu_env);
-        s->is_jmp = DISAS_JUMP;
+        s->base.jmp_type = DJ_JUMP;
         return;
     case 5: /* DRPS */
         if (rn != 0x1f) {
@@ -1800,7 +1801,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
         return;
     }
 
-    s->is_jmp = DISAS_JUMP;
+    s->base.jmp_type = DJ_JUMP;
 }
 
 /* C3.2 Branches, exception generating and system instructions */
@@ -2075,7 +2076,7 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
 
     tcg_rt = cpu_reg(s, rt);
 
-    tcg_addr = tcg_const_i64((s->pc - 4) + imm);
+    tcg_addr = tcg_const_i64((s->base.pc_next - 4) + imm);
     if (is_vector) {
         do_fp_ld(s, rt, tcg_addr, size);
     } else {
@@ -2893,7 +2894,7 @@ static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
     offset = sextract64(insn, 5, 19);
     offset = offset << 2 | extract32(insn, 29, 2);
     rd = extract32(insn, 0, 5);
-    base = s->pc - 4;
+    base = s->base.pc_next - 4;
 
     if (page) {
         /* ADRP (page based) */
@@ -11149,9 +11150,9 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
 {
     uint32_t insn;
 
-    insn = arm_ldl_code(env, s->pc, s->sctlr_b);
+    insn = arm_ldl_code(env, s->base.pc_next, s->sctlr_b);
     s->insn = insn;
-    s->pc += 4;
+    s->base.pc_next += 4;
 
     s->fp_access_checked = false;
 
@@ -11188,23 +11189,16 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
     free_tmp_a64(s);
 }
 
-void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb)
-{
-    CPUState *cs = CPU(cpu);
-    CPUARMState *env = &cpu->env;
-    DisasContext dc1, *dc = &dc1;
-    target_ulong pc_start;
-    target_ulong next_page_start;
-    int num_insns;
-    int max_insns;
 
-    pc_start = tb->pc;
 
-    dc->tb = tb;
+/* 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
 
-    dc->is_jmp = DISAS_NEXT;
-    dc->pc = pc_start;
-    dc->singlestep_enabled = cs->singlestep_enabled;
+static void gen_intermediate_code_target_init_disas_context(
+    DisasContext *dc, CPUArchState *env)
+{
     dc->condjmp = 0;
 
     dc->aarch64 = 1;
@@ -11215,20 +11209,20 @@ void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb)
                                !arm_el_is_aa64(env, 3);
     dc->thumb = 0;
     dc->sctlr_b = 0;
-    dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
+    dc->be_data = ARM_TBFLAG_BE_DATA(dc->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(tb->flags));
-    dc->tbi0 = ARM_TBFLAG_TBI0(tb->flags);
-    dc->tbi1 = ARM_TBFLAG_TBI1(tb->flags);
+    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->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(tb->flags);
+    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
     dc->vec_len = 0;
     dc->vec_stride = 0;
-    dc->cp_regs = cpu->cp_regs;
+    dc->cp_regs = arm_env_get_cpu(env)->cp_regs;
     dc->features = env->features;
 
     /* Single step state. The code-generation logic here is:
@@ -11246,146 +11240,148 @@ void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb)
      *   emit code to generate a software step exception
      *   end the TB
      */
-    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(tb->flags);
-    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(tb->flags);
+    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
+    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
     dc->is_ldex = false;
     dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
 
     init_tmp_a64_array(dc);
 
-    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
-    num_insns = 0;
-    max_insns = 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;
-    }
-
-    gen_tb_start(tb);
-
-    tcg_clear_temp_count();
-
-    do {
-        dc->insn_start_idx = tcg_op_buf_count();
-        tcg_gen_insn_start(dc->pc, 0, 0);
-        num_insns++;
+    dc->next_page_start =
+        (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+}
 
-        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
-            CPUBreakpoint *bp;
-            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
-                if (bp->pc == dc->pc) {
-                    if (bp->flags & BP_CPU) {
-                        gen_a64_set_pc_im(dc->pc);
-                        gen_helper_check_breakpoints(cpu_env);
-                        /* End the TB early; it likely won't be executed */
-                        dc->is_jmp = DISAS_UPDATE;
-                    } else {
-                        gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
-                        /* 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 += 4;
-                        goto done_generating;
-                    }
-                    break;
-                }
-            }
-        }
+static void gen_intermediate_code_target_init_globals(
+    DisasContext *dc, CPUArchState *env)
+{
+}
 
-        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
-            gen_io_start();
-        }
+static void gen_intermediate_code_target_tb_start(
+    DisasContext *dc, CPUArchState *env)
+{
+}
 
-        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
-             *  a) we just took an exception to an EL which is being debugged
-             *     and this is the first insn in the exception handler
-             *  b) debug exceptions were masked and we just unmasked them
-             *     without changing EL (eg by clearing PSTATE.D)
-             * In either case we're going to take a swstep exception in the
-             * "did not step an insn" case, and so the syndrome ISV and EX
-             * bits should be zero.
-             */
-            assert(num_insns == 1);
-            gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
-                          default_exception_el(dc));
-            dc->is_jmp = DISAS_EXC;
-            break;
-        }
+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);
+}
 
+static BreakpointHitType gen_intermediate_code_target_breakpoint_hit(
+    DisasContext *dc, CPUArchState *env,
+    const CPUBreakpoint *bp)
+{
+    if (bp->flags & BP_CPU) {
+        gen_a64_set_pc_im(dc->base.pc_next);
+        gen_helper_check_breakpoints(cpu_env);
+        /* End the TB early; it likely won't be executed */
+        dc->base.jmp_type = DJ_UPDATE;
+        return BH_HIT_INSN;
+    } else {
+        gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
+        /* 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->base.pc_next += 4;
+        return BH_HIT_TB;
+    }
+}
+
+static target_ulong gen_intermediate_code_target_disas_insn(
+    DisasContext *dc, CPUArchState *env)
+{
+    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
+         *  a) we just took an exception to an EL which is being debugged
+         *     and this is the first insn in the exception handler
+         *  b) debug exceptions were masked and we just unmasked them
+         *     without changing EL (eg by clearing PSTATE.D)
+         * In either case we're going to take a swstep exception in the
+         * "did not step an insn" case, and so the syndrome ISV and EX
+         * bits should be zero.
+         */
+        assert(dc->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;
+    } else {
         disas_a64_insn(env, dc);
+    }
+    return dc->base.pc_next;
+}
 
-        if (tcg_check_temp_count()) {
-            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
-                    dc->pc);
-        }
-
-        /* 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.
-         */
-    } while (!dc->is_jmp && !tcg_op_buf_full() &&
-             !cs->singlestep_enabled &&
-             !singlestep &&
-             !dc->ss_active &&
-             dc->pc < next_page_start &&
-             num_insns < max_insns);
-
-    if (tb->cflags & CF_LAST_IO) {
-        gen_io_end();
+static DisasJumpType gen_intermediate_code_target_stop_check(
+    DisasContext *dc, CPUArchState *env)
+{
+    /* 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.
+     */
+    if (dc->ss_active) {
+        return DJ_SS;
+    } else {
+        return dc->base.jmp_type;
     }
+}
 
-    if (unlikely(cs->singlestep_enabled || dc->ss_active)
-        && dc->is_jmp != DISAS_EXC) {
+static void gen_intermediate_code_target_stop(
+    DisasContext *dc, CPUArchState *env)
+{
+    if (unlikely(dc->base.singlestep_enabled || dc->ss_active)
+        && dc->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->is_jmp != DISAS_TB_JUMP);
-        if (dc->is_jmp != DISAS_JUMP) {
-            gen_a64_set_pc_im(dc->pc);
+        assert(dc->base.jmp_type != DJ_TB_JUMP);
+        if (dc->base.jmp_type != DJ_JUMP) {
+            gen_a64_set_pc_im(dc->base.pc_next);
         }
-        if (cs->singlestep_enabled) {
+        if (dc->base.singlestep_enabled) {
             gen_exception_internal(EXCP_DEBUG);
         } else {
             gen_step_complete_exception(dc);
         }
     } else {
-        switch (dc->is_jmp) {
-        case DISAS_NEXT:
-            gen_goto_tb(dc, 1, dc->pc);
+        /* Cast because target-specific values are not in generic enum */
+        unsigned int jt = (unsigned int)dc->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);
             break;
         default:
-        case DISAS_UPDATE:
-            gen_a64_set_pc_im(dc->pc);
+        case DJ_UPDATE:
+            gen_a64_set_pc_im(dc->base.pc_next);
             /* fall through */
-        case DISAS_JUMP:
+        case DJ_JUMP:
             tcg_gen_lookup_and_goto_ptr(cpu_pc);
             break;
-        case DISAS_TB_JUMP:
-        case DISAS_EXC:
-        case DISAS_SWI:
+        case DJ_TB_JUMP:
+        case DJ_EXC:
+        case DJ_SWI:
+            /* nothing to generate */
             break;
-        case DISAS_WFE:
-            gen_a64_set_pc_im(dc->pc);
+        case DJ_WFE:
+            gen_a64_set_pc_im(dc->base.pc_next);
             gen_helper_wfe(cpu_env);
             break;
-        case DISAS_YIELD:
-            gen_a64_set_pc_im(dc->pc);
+        case DJ_YIELD:
+            gen_a64_set_pc_im(dc->base.pc_next);
             gen_helper_yield(cpu_env);
             break;
-        case DISAS_WFI:
+        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->pc);
+            gen_a64_set_pc_im(dc->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.
@@ -11394,22 +11390,10 @@ void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb)
             break;
         }
     }
+}
 
-done_generating:
-    gen_tb_end(tb, num_insns);
-
-#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,
-                         4 | (bswap_code(dc->sctlr_b) ? 2 : 0));
-        qemu_log("\n");
-        qemu_log_unlock();
-    }
-#endif
-    tb->size = dc->pc - pc_start;
-    tb->icount = num_insns;
+static int gen_intermediate_code_target_get_disas_flags(
+    const DisasContext *dc)
+{
+    return 4 | (bswap_code(dc->sctlr_b) ? 2 : 0);
 }
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 96272a9888..06f207a5f6 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -196,9 +196,9 @@ static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
         uint32_t addr;
         /* normally, since we updated PC, we need only to add one insn */
         if (s->thumb)
-            addr = (long)s->pc + 2;
+            addr = (long)s->base.pc_next + 2;
         else
-            addr = (long)s->pc + 4;
+            addr = (long)s->base.pc_next + 4;
         tcg_gen_movi_i32(var, addr);
     } else {
         tcg_gen_mov_i32(var, cpu_R[reg]);
@@ -224,7 +224,7 @@ static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
          * We choose to ignore [1:0] in ARM mode for all architecture versions.
          */
         tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
-        s->is_jmp = DISAS_JUMP;
+        s->base.jmp_type = DJ_JUMP;
     }
     tcg_gen_mov_i32(cpu_R[reg], var);
     tcg_temp_free_i32(var);
@@ -297,7 +297,7 @@ static void gen_step_complete_exception(DisasContext *s)
     gen_ss_advance(s);
     gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
                   default_exception_el(s));
-    s->is_jmp = DISAS_EXC;
+    s->base.jmp_type = DJ_EXC;
 }
 
 static void gen_singlestep_exception(DisasContext *s)
@@ -321,7 +321,7 @@ static inline bool is_singlestepping(DisasContext *s)
      * misnamed as it only means "one instruction per TB" and doesn't
      * affect the code we generate.
      */
-    return s->singlestep_enabled || s->ss_active;
+    return s->base.singlestep_enabled || s->ss_active;
 }
 
 static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
@@ -928,7 +928,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
 {
     TCGv_i32 tmp;
 
-    s->is_jmp = DISAS_JUMP;
+    s->base.jmp_type = DJ_JUMP;
     if (s->thumb != (addr & 1)) {
         tmp = tcg_temp_new_i32();
         tcg_gen_movi_i32(tmp, addr & 1);
@@ -941,7 +941,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
 /* Set PC and Thumb state from var.  var is marked as dead.  */
 static inline void gen_bx(DisasContext *s, TCGv_i32 var)
 {
-    s->is_jmp = DISAS_JUMP;
+    s->base.jmp_type = DJ_JUMP;
     tcg_gen_andi_i32(cpu_R[15], var, ~1);
     tcg_gen_andi_i32(var, var, 1);
     store_cpu_field(var, thumb);
@@ -955,11 +955,11 @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var)
 static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)
 {
     /* Generate the same code here as for a simple bx, but flag via
-     * s->is_jmp that we need to do the rest of the work later.
+     * s->base.jmp_type that we need to do the rest of the work later.
      */
     gen_bx(s, var);
     if (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M)) {
-        s->is_jmp = DISAS_BX_EXCRET;
+        s->base.jmp_type = DJ_BX_EXCRET;
     }
 }
 
@@ -1150,7 +1150,7 @@ static inline void gen_hvc(DisasContext *s, int imm16)
      * as an undefined insn by runtime configuration (ie before
      * the insn really executes).
      */
-    gen_set_pc_im(s, s->pc - 4);
+    gen_set_pc_im(s, s->base.pc_next - 4);
     gen_helper_pre_hvc(cpu_env);
     /* Otherwise we will treat this as a real exception which
      * happens after execution of the insn. (The distinction matters
@@ -1158,8 +1158,8 @@ static inline void gen_hvc(DisasContext *s, int imm16)
      * for single stepping.)
      */
     s->svc_imm = imm16;
-    gen_set_pc_im(s, s->pc);
-    s->is_jmp = DISAS_HVC;
+    gen_set_pc_im(s, s->base.pc_next);
+    s->base.jmp_type = DJ_HVC;
 }
 
 static inline void gen_smc(DisasContext *s)
@@ -1169,36 +1169,36 @@ static inline void gen_smc(DisasContext *s)
      */
     TCGv_i32 tmp;
 
-    gen_set_pc_im(s, s->pc - 4);
+    gen_set_pc_im(s, s->base.pc_next - 4);
     tmp = tcg_const_i32(syn_aa32_smc());
     gen_helper_pre_smc(cpu_env, tmp);
     tcg_temp_free_i32(tmp);
-    gen_set_pc_im(s, s->pc);
-    s->is_jmp = DISAS_SMC;
+    gen_set_pc_im(s, s->base.pc_next);
+    s->base.jmp_type = DJ_SMC;
 }
 
 static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
 {
     gen_set_condexec(s);
-    gen_set_pc_im(s, s->pc - offset);
+    gen_set_pc_im(s, s->base.pc_next - offset);
     gen_exception_internal(excp);
-    s->is_jmp = DISAS_EXC;
+    s->base.jmp_type = DJ_EXC;
 }
 
 static void gen_exception_insn(DisasContext *s, int offset, int excp,
                                int syn, uint32_t target_el)
 {
     gen_set_condexec(s);
-    gen_set_pc_im(s, s->pc - offset);
+    gen_set_pc_im(s, s->base.pc_next - offset);
     gen_exception(excp, syn, target_el);
-    s->is_jmp = DISAS_EXC;
+    s->base.jmp_type = DJ_EXC;
 }
 
 /* Force a TB lookup after an instruction that changes the CPU state.  */
 static inline void gen_lookup_tb(DisasContext *s)
 {
-    tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
-    s->is_jmp = DISAS_EXIT;
+    tcg_gen_movi_i32(cpu_R[15], s->base.pc_next & ~1);
+    s->base.jmp_type = DJ_EXIT;
 }
 
 static inline void gen_hlt(DisasContext *s, int imm)
@@ -4053,7 +4053,7 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
                 if (s->thumb && rn == 15) {
                     /* This is actually UNPREDICTABLE */
                     addr = tcg_temp_new_i32();
-                    tcg_gen_movi_i32(addr, s->pc & ~2);
+                    tcg_gen_movi_i32(addr, s->base.pc_next & ~2);
                 } else {
                     addr = load_reg(s, rn);
                 }
@@ -4092,7 +4092,7 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
                 if (s->thumb && rn == 15) {
                     /* This is actually UNPREDICTABLE */
                     addr = tcg_temp_new_i32();
-                    tcg_gen_movi_i32(addr, s->pc & ~2);
+                    tcg_gen_movi_i32(addr, s->base.pc_next & ~2);
                 } else {
                     addr = load_reg(s, rn);
                 }
@@ -4143,8 +4143,9 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
 static inline bool use_goto_tb(DisasContext *s, target_ulong dest)
 {
 #ifndef CONFIG_USER_ONLY
-    return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
-           ((s->pc - 1) & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
+    return
+        (s->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
+        ((s->base.pc_next - 1) & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
 #else
     return true;
 #endif
@@ -4163,7 +4164,7 @@ static void gen_goto_tb(DisasContext *s, int n, target_ulong dest)
     if (use_goto_tb(s, dest)) {
         tcg_gen_goto_tb(n);
         gen_set_pc_im(s, dest);
-        tcg_gen_exit_tb((uintptr_t)s->tb + n);
+        tcg_gen_exit_tb((uintptr_t)s->base.tb + n);
     } else {
         gen_set_pc_im(s, dest);
         gen_goto_ptr();
@@ -4179,7 +4180,7 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest)
         gen_bx_im(s, dest);
     } else {
         gen_goto_tb(s, 0, dest);
-        s->is_jmp = DISAS_TB_JUMP;
+        s->base.jmp_type = DJ_TB_JUMP;
     }
 }
 
@@ -4422,7 +4423,7 @@ static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn)
 
     /* Sync state because msr_banked() can raise exceptions */
     gen_set_condexec(s);
-    gen_set_pc_im(s, s->pc - 4);
+    gen_set_pc_im(s, s->base.pc_next - 4);
     tcg_reg = load_reg(s, rn);
     tcg_tgtmode = tcg_const_i32(tgtmode);
     tcg_regno = tcg_const_i32(regno);
@@ -4430,7 +4431,7 @@ static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn)
     tcg_temp_free_i32(tcg_tgtmode);
     tcg_temp_free_i32(tcg_regno);
     tcg_temp_free_i32(tcg_reg);
-    s->is_jmp = DISAS_UPDATE;
+    s->base.jmp_type = DJ_UPDATE;
 }
 
 static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
@@ -4444,7 +4445,7 @@ static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
 
     /* Sync state because mrs_banked() can raise exceptions */
     gen_set_condexec(s);
-    gen_set_pc_im(s, s->pc - 4);
+    gen_set_pc_im(s, s->base.pc_next - 4);
     tcg_reg = tcg_temp_new_i32();
     tcg_tgtmode = tcg_const_i32(tgtmode);
     tcg_regno = tcg_const_i32(regno);
@@ -4452,7 +4453,7 @@ static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
     tcg_temp_free_i32(tcg_tgtmode);
     tcg_temp_free_i32(tcg_regno);
     store_reg(s, rn, tcg_reg);
-    s->is_jmp = DISAS_UPDATE;
+    s->base.jmp_type = DJ_UPDATE;
 }
 
 /* Store value to PC as for an exception return (ie don't
@@ -4475,7 +4476,7 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
      */
     gen_helper_cpsr_write_eret(cpu_env, cpsr);
     tcg_temp_free_i32(cpsr);
-    s->is_jmp = DISAS_JUMP;
+    s->base.jmp_type = DJ_JUMP;
 }
 
 /* Generate an old-style exception return. Marks pc as dead. */
@@ -4497,18 +4498,18 @@ static void gen_nop_hint(DisasContext *s, int val)
     switch (val) {
     case 1: /* yield */
         if (!parallel_cpus) {
-            gen_set_pc_im(s, s->pc);
-            s->is_jmp = DISAS_YIELD;
+            gen_set_pc_im(s, s->base.pc_next);
+            s->base.jmp_type = DJ_YIELD;
         }
         break;
     case 3: /* wfi */
-        gen_set_pc_im(s, s->pc);
-        s->is_jmp = DISAS_WFI;
+        gen_set_pc_im(s, s->base.pc_next);
+        s->base.jmp_type = DJ_WFI;
         break;
     case 2: /* wfe */
         if (!parallel_cpus) {
-            gen_set_pc_im(s, s->pc);
-            s->is_jmp = DISAS_WFE;
+            gen_set_pc_im(s, s->base.pc_next);
+            s->base.jmp_type = DJ_WFE;
         }
         break;
     case 4: /* sev */
@@ -7627,7 +7628,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
             }
 
             gen_set_condexec(s);
-            gen_set_pc_im(s, s->pc - 4);
+            gen_set_pc_im(s, s->base.pc_next - 4);
             tmpptr = tcg_const_ptr(ri);
             tcg_syn = tcg_const_i32(syndrome);
             tcg_isread = tcg_const_i32(isread);
@@ -7646,14 +7647,14 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
             if (isread) {
                 return 1;
             }
-            gen_set_pc_im(s, s->pc);
-            s->is_jmp = DISAS_WFI;
+            gen_set_pc_im(s, s->base.pc_next);
+            s->base.jmp_type = DJ_WFI;
             return 0;
         default:
             break;
         }
 
-        if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
+        if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
             gen_io_start();
         }
 
@@ -7744,7 +7745,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
             }
         }
 
-        if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
+        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_lookup_tb(s);
@@ -8008,7 +8009,7 @@ static void gen_srs(DisasContext *s,
     tmp = tcg_const_i32(mode);
     /* get_r13_banked() will raise an exception if called from System mode */
     gen_set_condexec(s);
-    gen_set_pc_im(s, s->pc - 4);
+    gen_set_pc_im(s, s->base.pc_next - 4);
     gen_helper_get_r13_banked(addr, cpu_env, tmp);
     tcg_temp_free_i32(tmp);
     switch (amode) {
@@ -8058,7 +8059,7 @@ static void gen_srs(DisasContext *s,
         tcg_temp_free_i32(tmp);
     }
     tcg_temp_free_i32(addr);
-    s->is_jmp = DISAS_UPDATE;
+    s->base.jmp_type = DJ_UPDATE;
 }
 
 static void disas_arm_insn(DisasContext *s, unsigned int insn)
@@ -8146,7 +8147,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
             /* setend */
             if (((insn >> 9) & 1) != !!(s->be_data == MO_BE)) {
                 gen_helper_setend(cpu_env);
-                s->is_jmp = DISAS_UPDATE;
+                s->base.jmp_type = DJ_UPDATE;
             }
             return;
         } else if ((insn & 0x0fffff00) == 0x057ff000) {
@@ -8220,7 +8221,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
             /* branch link and change to thumb (blx <offset>) */
             int32_t offset;
 
-            val = (uint32_t)s->pc;
+            val = (uint32_t)s->base.pc_next;
             tmp = tcg_temp_new_i32();
             tcg_gen_movi_i32(tmp, val);
             store_reg(s, 14, tmp);
@@ -8398,7 +8399,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
             /* branch link/exchange thumb (blx) */
             tmp = load_reg(s, rm);
             tmp2 = tcg_temp_new_i32();
-            tcg_gen_movi_i32(tmp2, s->pc);
+            tcg_gen_movi_i32(tmp2, s->base.pc_next);
             store_reg(s, 14, tmp2);
             gen_bx(s, tmp);
             break;
@@ -9468,7 +9469,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
                             /* store */
                             if (i == 15) {
                                 /* special case: r15 = PC + 8 */
-                                val = (long)s->pc + 4;
+                                val = (long)s->base.pc_next + 4;
                                 tmp = tcg_temp_new_i32();
                                 tcg_gen_movi_i32(tmp, val);
                             } else if (user) {
@@ -9519,7 +9520,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
                     tmp = load_cpu_field(spsr);
                     gen_helper_cpsr_write_eret(cpu_env, tmp);
                     tcg_temp_free_i32(tmp);
-                    s->is_jmp = DISAS_JUMP;
+                    s->base.jmp_type = DJ_JUMP;
                 }
             }
             break;
@@ -9529,7 +9530,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
                 int32_t offset;
 
                 /* branch (and link) */
-                val = (int32_t)s->pc;
+                val = (int32_t)s->base.pc_next;
                 if (insn & (1 << 24)) {
                     tmp = tcg_temp_new_i32();
                     tcg_gen_movi_i32(tmp, val);
@@ -9555,9 +9556,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
             break;
         case 0xf:
             /* swi */
-            gen_set_pc_im(s, s->pc);
+            gen_set_pc_im(s, s->base.pc_next);
             s->svc_imm = extract32(insn, 0, 24);
-            s->is_jmp = DISAS_SWI;
+            s->base.jmp_type = DJ_SWI;
             break;
         default:
         illegal_op:
@@ -9681,7 +9682,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
             tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
 
             tmp2 = tcg_temp_new_i32();
-            tcg_gen_movi_i32(tmp2, s->pc | 1);
+            tcg_gen_movi_i32(tmp2, s->base.pc_next | 1);
             store_reg(s, 14, tmp2);
             gen_bx(s, tmp);
             return 0;
@@ -9693,24 +9694,24 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
             tcg_gen_addi_i32(tmp, tmp, offset);
 
             tmp2 = tcg_temp_new_i32();
-            tcg_gen_movi_i32(tmp2, s->pc | 1);
+            tcg_gen_movi_i32(tmp2, s->base.pc_next | 1);
             store_reg(s, 14, tmp2);
             gen_bx(s, tmp);
             return 0;
         }
-        if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
+        if ((s->base.pc_next & ~TARGET_PAGE_MASK) == 0) {
             /* Instruction spans a page boundary.  Implement it as two
                16-bit instructions in case the second half causes an
                prefetch abort.  */
             offset = ((int32_t)insn << 21) >> 9;
-            tcg_gen_movi_i32(cpu_R[14], s->pc + 2 + offset);
+            tcg_gen_movi_i32(cpu_R[14], s->base.pc_next + 2 + offset);
             return 0;
         }
         /* Fall through to 32-bit decode.  */
     }
 
-    insn = arm_lduw_code(env, s->pc, s->sctlr_b);
-    s->pc += 2;
+    insn = arm_lduw_code(env, s->base.pc_next, s->sctlr_b);
+    s->base.pc_next += 2;
     insn |= (uint32_t)insn_hw1 << 16;
 
     if ((insn & 0xf800e800) != 0xf000e800) {
@@ -9732,7 +9733,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                 /* Load/store doubleword.  */
                 if (rn == 15) {
                     addr = tcg_temp_new_i32();
-                    tcg_gen_movi_i32(addr, s->pc & ~3);
+                    tcg_gen_movi_i32(addr, s->base.pc_next & ~3);
                 } else {
                     addr = load_reg(s, rn);
                 }
@@ -9786,7 +9787,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                 /* Table Branch.  */
                 if (rn == 15) {
                     addr = tcg_temp_new_i32();
-                    tcg_gen_movi_i32(addr, s->pc);
+                    tcg_gen_movi_i32(addr, s->base.pc_next);
                 } else {
                     addr = load_reg(s, rn);
                 }
@@ -9805,7 +9806,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                 }
                 tcg_temp_free_i32(addr);
                 tcg_gen_shli_i32(tmp, tmp, 1);
-                tcg_gen_addi_i32(tmp, tmp, s->pc);
+                tcg_gen_addi_i32(tmp, tmp, s->base.pc_next);
                 store_reg(s, 15, tmp);
             } else {
                 int op2 = (insn >> 6) & 0x3;
@@ -10438,10 +10439,10 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
 
                 if (insn & (1 << 14)) {
                     /* Branch and link.  */
-                    tcg_gen_movi_i32(cpu_R[14], s->pc | 1);
+                    tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1);
                 }
 
-                offset += s->pc;
+                offset += s->base.pc_next;
                 if (insn & (1 << 12)) {
                     /* b/bl */
                     gen_jmp(s, offset);
@@ -10662,7 +10663,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                 offset |= (insn & (1 << 11)) << 8;
 
                 /* jump to the offset */
-                gen_jmp(s, s->pc + offset);
+                gen_jmp(s, s->base.pc_next + offset);
             }
         } else {
             /* Data processing immediate.  */
@@ -10765,7 +10766,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                     } else {
                         /* Add/sub 12-bit immediate.  */
                         if (rn == 15) {
-                            offset = s->pc & ~(uint32_t)3;
+                            offset = s->base.pc_next & ~(uint32_t)3;
                             if (insn & (1 << 23))
                                 offset -= imm;
                             else
@@ -10887,8 +10888,8 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
         if (rn == 15) {
             addr = tcg_temp_new_i32();
             /* PC relative.  */
-            /* s->pc has already been incremented by 4.  */
-            imm = s->pc & 0xfffffffc;
+            /* s->base.pc_next has already been incremented by 4.  */
+            imm = s->base.pc_next & 0xfffffffc;
             if (insn & (1 << 23))
                 imm += insn & 0xfff;
             else
@@ -11029,8 +11030,8 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
         }
     }
 
-    insn = arm_lduw_code(env, s->pc, s->sctlr_b);
-    s->pc += 2;
+    insn = arm_lduw_code(env, s->base.pc_next, s->sctlr_b);
+    s->base.pc_next += 2;
 
     switch (insn >> 12) {
     case 0: case 1:
@@ -11117,7 +11118,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
         if (insn & (1 << 11)) {
             rd = (insn >> 8) & 7;
             /* load pc-relative.  Bit 1 of PC is ignored.  */
-            val = s->pc + 2 + ((insn & 0xff) * 4);
+            val = s->base.pc_next + 2 + ((insn & 0xff) * 4);
             val &= ~(uint32_t)2;
             addr = tcg_temp_new_i32();
             tcg_gen_movi_i32(addr, val);
@@ -11156,7 +11157,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
                 tmp = load_reg(s, rm);
                 if (insn & (1 << 7)) {
                     ARCH(5);
-                    val = (uint32_t)s->pc | 1;
+                    val = (uint32_t)s->base.pc_next | 1;
                     tmp2 = tcg_temp_new_i32();
                     tcg_gen_movi_i32(tmp2, val);
                     store_reg(s, 14, tmp2);
@@ -11456,7 +11457,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
         } else {
             /* PC. bit 1 is ignored.  */
             tmp = tcg_temp_new_i32();
-            tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
+            tcg_gen_movi_i32(tmp, (s->base.pc_next + 2) & ~(uint32_t)2);
         }
         val = (insn & 0xff) * 4;
         tcg_gen_addi_i32(tmp, tmp, val);
@@ -11559,7 +11560,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
                 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
             tcg_temp_free_i32(tmp);
             offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3;
-            val = (uint32_t)s->pc + 2;
+            val = (uint32_t)s->base.pc_next + 2;
             val += offset;
             gen_jmp(s, val);
             break;
@@ -11619,7 +11620,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
                 ARCH(6);
                 if (((insn >> 3) & 1) != !!(s->be_data == MO_BE)) {
                     gen_helper_setend(cpu_env);
-                    s->is_jmp = DISAS_UPDATE;
+                    s->base.jmp_type = DJ_UPDATE;
                 }
                 break;
             case 3:
@@ -11711,9 +11712,9 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
 
         if (cond == 0xf) {
             /* swi */
-            gen_set_pc_im(s, s->pc);
+            gen_set_pc_im(s, s->base.pc_next);
             s->svc_imm = extract32(insn, 0, 8);
-            s->is_jmp = DISAS_SWI;
+            s->base.jmp_type = DJ_SWI;
             break;
         }
         /* generate a conditional jump to next instruction */
@@ -11722,7 +11723,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
         s->condjmp = 1;
 
         /* jump to the offset */
-        val = (uint32_t)s->pc + 2;
+        val = (uint32_t)s->base.pc_next + 2;
         offset = ((int32_t)insn << 24) >> 24;
         val += offset << 1;
         gen_jmp(s, val);
@@ -11735,7 +11736,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
             break;
         }
         /* unconditional branch */
-        val = (uint32_t)s->pc;
+        val = (uint32_t)s->base.pc_next;
         offset = ((int32_t)insn << 21) >> 21;
         val += (offset << 1) + 2;
         gen_jmp(s, val);
@@ -11757,20 +11758,20 @@ undef:
                        default_exception_el(s));
 }
 
-static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
+static bool insn_crosses_page(CPUARMState *env, const DisasContext *s)
 {
     /* Return true if the insn at dc->pc might cross a page boundary.
      * (False positives are OK, false negatives are not.)
      */
     uint16_t insn;
 
-    if ((s->pc & 3) == 0) {
+    if ((s->base.pc_next & 3) == 0) {
         /* At a 4-aligned address we can't be crossing a page */
         return false;
     }
 
     /* This must be a Thumb insn */
-    insn = arm_lduw_code(env, s->pc, s->sctlr_b);
+    insn = arm_lduw_code(env, s->base.pc_next, s->sctlr_b);
 
     if ((insn >> 11) >= 0x1d) {
         /* Top five bits 0b11101 / 0b11110 / 0b11111 : this is the
@@ -11786,35 +11787,108 @@ static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
     return false;
 }
 
-/* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
-{
-    CPUARMState *env = cpu->env_ptr;
-    ARMCPU *arm_cpu = arm_env_get_cpu(env);
-    DisasContext dc1, *dc = &dc1;
-    target_ulong pc_start;
-    target_ulong next_page_start;
-    int num_insns;
-    int max_insns;
-    bool end_of_page;
+static const char *cpu_mode_names[16] = {
+  "usr", "fiq", "irq", "svc", "???", "???", "mon", "abt",
+  "???", "???", "hyp", "und", "???", "???", "???", "sys"
+};
 
-    /* generate intermediate code */
+void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
+                        int flags)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    int i;
+    uint32_t psr;
+    const char *ns_status;
 
-    /* The A64 decoder has its own top level loop, because it doesn't need
-     * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
-     */
-    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
-        gen_intermediate_code_a64(arm_cpu, tb);
+    if (is_a64(env)) {
+        aarch64_cpu_dump_state(cs, f, cpu_fprintf, flags);
         return;
     }
 
-    pc_start = tb->pc;
+    for (i = 0; i < 16; i++) {
+        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
+        if ((i % 4) == 3) {
+            cpu_fprintf(f, "\n");
+        } else {
+            cpu_fprintf(f, " ");
+        }
+    }
+    psr = cpsr_read(env);
+
+    if (arm_feature(env, ARM_FEATURE_EL3) &&
+        (psr & CPSR_M) != ARM_CPU_MODE_MON) {
+        ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
+    } else {
+        ns_status = "";
+    }
 
-    dc->tb = tb;
+    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
+                psr,
+                psr & (1 << 31) ? 'N' : '-',
+                psr & (1 << 30) ? 'Z' : '-',
+                psr & (1 << 29) ? 'C' : '-',
+                psr & (1 << 28) ? 'V' : '-',
+                psr & CPSR_T ? 'T' : 'A',
+                ns_status,
+                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
 
-    dc->is_jmp = DISAS_NEXT;
-    dc->pc = pc_start;
-    dc->singlestep_enabled = cpu->singlestep_enabled;
+    if (flags & CPU_DUMP_FPU) {
+        int numvfpregs = 0;
+        if (arm_feature(env, ARM_FEATURE_VFP)) {
+            numvfpregs += 16;
+        }
+        if (arm_feature(env, ARM_FEATURE_VFP3)) {
+            numvfpregs += 16;
+        }
+        for (i = 0; i < numvfpregs; i++) {
+            uint64_t v = float64_val(env->vfp.regs[i]);
+            cpu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
+                        i * 2, (uint32_t)v,
+                        i * 2 + 1, (uint32_t)(v >> 32),
+                        i, v);
+        }
+        cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
+    }
+}
+
+void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb,
+                          target_ulong *data)
+{
+    if (is_a64(env)) {
+        env->pc = data[0];
+        env->condexec_bits = 0;
+    } else {
+        env->regs[15] = data[0];
+        env->condexec_bits = data[1];
+    }
+}
+
+
+
+/* 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)
+{
+    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
+        gen_intermediate_code_aarch64(cpu, tb);
+    } else {
+        gen_intermediate_code_arm(cpu, tb);
+    }
+}
+
+static void gen_intermediate_code_target_init_disas_context(
+    DisasContext *dc, CPUARMState *env)
+{
     dc->condjmp = 0;
 
     dc->aarch64 = 0;
@@ -11822,25 +11896,25 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
      * there is no secure EL1, so we route exceptions to EL3.
      */
     dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
-                               !arm_el_is_aa64(env, 3);
-    dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
-    dc->sctlr_b = ARM_TBFLAG_SCTLR_B(tb->flags);
-    dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
-    dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
-    dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
-    dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(tb->flags));
+        !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->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(tb->flags);
-    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(tb->flags);
-    dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
-    dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
-    dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
-    dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(tb->flags);
-    dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(tb->flags);
-    dc->cp_regs = arm_cpu->cp_regs;
+    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->cp_regs = arm_env_get_cpu(env)->cp_regs;
     dc->features = env->features;
 
     /* Single step state. The code-generation logic here is:
@@ -11858,11 +11932,18 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
      *   emit code to generate a software step exception
      *   end the TB
      */
-    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(tb->flags);
-    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(tb->flags);
+    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
+    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->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;
+}
+
+static void gen_intermediate_code_target_init_globals(
+    DisasContext *dc, CPUARMState *env)
+{
     cpu_F0s = tcg_temp_new_i32();
     cpu_F1s = tcg_temp_new_i32();
     cpu_F0d = tcg_temp_new_i64();
@@ -11871,20 +11952,11 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
     cpu_V1 = cpu_F1d;
     /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
     cpu_M0 = tcg_temp_new_i64();
-    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
-    num_insns = 0;
-    max_insns = 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;
-    }
-
-    gen_tb_start(tb);
-
-    tcg_clear_temp_count();
+}
 
+static void gen_intermediate_code_target_tb_start(
+    DisasContext *dc, CPUARMState *env)
+{
     /* A note on handling of the condexec (IT) bits:
      *
      * We want to avoid the overhead of having to write the updated condexec
@@ -11915,111 +11987,130 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
      * middle of a TB.
      */
 
-    /* Reset the conditional execution bits immediately. This avoids
-       complications trying to do it at the end of the block.  */
-    if (dc->condexec_mask || dc->condexec_cond)
-      {
+    /*
+     * Reset the conditional execution bits immediately. This avoids
+     * complications trying to do it at the end of the block.
+     */
+    if (dc->condexec_mask || dc->condexec_cond) {
         TCGv_i32 tmp = tcg_temp_new_i32();
         tcg_gen_movi_i32(tmp, 0);
         store_cpu_field(tmp, condexec_bits);
-      }
-    do {
-        dc->insn_start_idx = tcg_op_buf_count();
-        tcg_gen_insn_start(dc->pc,
-                           (dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
-                           0);
-        num_insns++;
+    }
+}
 
-#ifdef CONFIG_USER_ONLY
-        /* Intercept jump to the magic kernel page.  */
-        if (dc->pc >= 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->is_jmp = DISAS_EXC;
-            break;
-        }
-#endif
+static void gen_intermediate_code_target_insn_start(
+    DisasContext *dc, CPUARMState *env)
+{
+    dc->insn_start_idx = tcg_op_buf_count();
+    tcg_gen_insn_start(dc->base.pc_next,
+                       (dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
+                       0);
 
-        if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
-            CPUBreakpoint *bp;
-            QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
-                if (bp->pc == dc->pc) {
-                    if (bp->flags & BP_CPU) {
-                        gen_set_condexec(dc);
-                        gen_set_pc_im(dc, dc->pc);
-                        gen_helper_check_breakpoints(cpu_env);
-                        /* End the TB early; it's likely not going to be executed */
-                        dc->is_jmp = DISAS_UPDATE;
-                    } else {
-                        gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
-                        /* 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.  */
-                        /* TODO: Advance PC by correct instruction length to
-                         * avoid disassembler error messages */
-                        dc->pc += 2;
-                        goto done_generating;
-                    }
-                    break;
-                }
-            }
-        }
 
-        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
-            gen_io_start();
-        }
+#ifdef CONFIG_USER_ONLY
+    /* Intercept jump to the magic kernel page.  */
+    if (dc->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;
+    }
+#else
+    if (dc->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;
+    }
+#endif
+}
 
-        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
-             *  a) we just took an exception to an EL which is being debugged
-             *     and this is the first insn in the exception handler
-             *  b) debug exceptions were masked and we just unmasked them
-             *     without changing EL (eg by clearing PSTATE.D)
-             * In either case we're going to take a swstep exception in the
-             * "did not step an insn" case, and so the syndrome ISV and EX
-             * bits should be zero.
-             */
-            assert(num_insns == 1);
-            gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
-                          default_exception_el(dc));
-            goto done_generating;
-        }
+static BreakpointHitType gen_intermediate_code_target_breakpoint_hit(
+    DisasContext *dc, CPUARMState *env,
+    const CPUBreakpoint *bp)
+{
+    if (bp->flags & BP_CPU) {
+        gen_set_condexec(dc);
+        gen_set_pc_im(dc, 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;
+        return BH_HIT_INSN;
+    } else {
+        gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
+        /* 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.  */
+        /* TODO: Advance PC by correct instruction length to avoid
+         * disassembler error messages */
+        dc->base.pc_next += 2;
+        return BH_HIT_TB;
+    }
+}
+
+static target_ulong gen_intermediate_code_target_disas_insn(
+    DisasContext *dc, CPUArchState *env)
+{
+    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
+         *  a) we just took an exception to an EL which is being debugged
+         *     and this is the first insn in the exception handler
+         *  b) debug exceptions were masked and we just unmasked them
+         *     without changing EL (eg by clearing PSTATE.D)
+         * In either case we're going to take a swstep exception in the
+         * "did not step an insn" case, and so the syndrome ISV and EX
+         * bits should be zero.
+         */
+        assert(dc->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;
+    }
 
-        if (dc->thumb) {
-            disas_thumb_insn(env, dc);
-            if (dc->condexec_mask) {
-                dc->condexec_cond = (dc->condexec_cond & 0xe)
-                                   | ((dc->condexec_mask >> 4) & 1);
-                dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
-                if (dc->condexec_mask == 0) {
-                    dc->condexec_cond = 0;
-                }
+    if (dc->thumb) {
+        disas_thumb_insn(env, dc);
+        if (dc->condexec_mask) {
+            dc->condexec_cond = (dc->condexec_cond & 0xe)
+                | ((dc->condexec_mask >> 4) & 1);
+            dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
+            if (dc->condexec_mask == 0) {
+                dc->condexec_cond = 0;
             }
-        } else {
-            unsigned int insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
-            dc->pc += 4;
-            disas_arm_insn(dc, insn);
         }
+    } else {
+        unsigned int insn = arm_ldl_code(env, dc->base.pc_next, dc->sctlr_b);
+        dc->base.pc_next += 4;
+        disas_arm_insn(dc, insn);
+    }
 
-        if (dc->condjmp && !dc->is_jmp) {
-            gen_set_label(dc->condlabel);
-            dc->condjmp = 0;
-        }
+    if (dc->condjmp && !dc->base.jmp_type) {
+        gen_set_label(dc->condlabel);
+        dc->condjmp = 0;
+    }
 
-        if (tcg_check_temp_count()) {
-            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
-                    dc->pc);
-        }
+    return dc->base.pc_next;
+}
 
-        /* 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.  */
+static DisasJumpType gen_intermediate_code_target_stop_check(
+    DisasContext *dc, CPUARMState *env)
+{
+    /* 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.  */
 
+    if (is_singlestepping(dc)) {
+        return DJ_SS;
+    } else if ((dc->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
+         * page.
+         */
         /* We want to stop the TB if the next insn starts in a new page,
          * or if it spans between this page and the next. This means that
          * if we're looking at the last halfword in the page we need to
@@ -12029,29 +12120,32 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
          * in it at the end of this page (which would execute correctly
          * but isn't very efficient).
          */
-        end_of_page = (dc->pc >= next_page_start) ||
-            ((dc->pc >= next_page_start - 3) && insn_crosses_page(env, dc));
+        return DJ_PAGE_CROSS;
+    } else {
+        return dc->base.jmp_type;
+    }
+}
 
-    } while (!dc->is_jmp && !tcg_op_buf_full() &&
-             !is_singlestepping(dc) &&
-             !singlestep &&
-             !end_of_page &&
-             num_insns < max_insns);
+static void gen_intermediate_code_target_stop(
+    DisasContext *dc, CPUARMState *env)
+{
+    /* Cast because target-specific values are not in generic enum */
+    unsigned int jt = (unsigned int)dc->base.jmp_type;
 
-    if (tb->cflags & CF_LAST_IO) {
-        if (dc->condjmp) {
-            /* FIXME:  This can theoretically happen with self-modifying
-               code.  */
-            cpu_abort(cpu, "IO on conditional branch instruction");
-        }
-        gen_io_end();
+    if (jt == DJ_SKIP) {
+        return;
+    }
+
+    if ((dc->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");
     }
 
     /* At this stage dc->condjmp will only be set when the skipped
        instruction was a conditional branch or trap, and the PC has
        already been written.  */
     gen_set_condexec(dc);
-    if (dc->is_jmp == DISAS_BX_EXCRET) {
+    if (dc->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
@@ -12060,23 +12154,24 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
         gen_bx_excret_final_code(dc);
     } else if (unlikely(is_singlestepping(dc))) {
         /* Unconditional and "condition passed" instruction codepath. */
-        switch (dc->is_jmp) {
-        case DISAS_SWI:
+        switch (jt) {
+        case DJ_SWI:
             gen_ss_advance(dc);
             gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
                           default_exception_el(dc));
             break;
-        case DISAS_HVC:
+        case DJ_HVC:
             gen_ss_advance(dc);
             gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
             break;
-        case DISAS_SMC:
+        case DJ_SMC:
             gen_ss_advance(dc);
             gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
             break;
-        case DISAS_NEXT:
-        case DISAS_UPDATE:
-            gen_set_pc_im(dc, dc->pc);
+        case DJ_NEXT:
+        case DJ_TOO_MANY:               /* target set DJ_NEXT */
+        case DJ_UPDATE:
+            gen_set_pc_im(dc, dc->base.pc_next);
             /* fall through */
         default:
             /* FIXME: Single stepping a WFI insn will not halt the CPU. */
@@ -12091,45 +12186,48 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
             - Hardware watchpoints.
            Hardware breakpoints have already been handled and skip this code.
          */
-        switch(dc->is_jmp) {
-        case DISAS_NEXT:
-            gen_goto_tb(dc, 1, dc->pc);
+        gen_set_condexec(dc);
+
+        switch (jt) {
+        case DJ_NEXT:
+        case DJ_TOO_MANY:               /* target set DJ_NEXT */
+            gen_goto_tb(dc, 1, dc->base.pc_next);
             break;
-        case DISAS_UPDATE:
-            gen_set_pc_im(dc, dc->pc);
+        case DJ_UPDATE:
+            gen_set_pc_im(dc, dc->base.pc_next);
             /* fall through */
-        case DISAS_JUMP:
+        case DJ_JUMP:
             gen_goto_ptr();
             break;
         default:
             /* indicate that the hash table must be used to find the next TB */
             tcg_gen_exit_tb(0);
             break;
-        case DISAS_TB_JUMP:
-        case DISAS_EXC:
+        case DJ_TB_JUMP:
+        case DJ_EXC:
             /* nothing more to generate */
             break;
-        case DISAS_WFI:
+        case DJ_WFI:
             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.
              */
             tcg_gen_exit_tb(0);
             break;
-        case DISAS_WFE:
+        case DJ_WFE:
             gen_helper_wfe(cpu_env);
             break;
-        case DISAS_YIELD:
+        case DJ_YIELD:
             gen_helper_yield(cpu_env);
             break;
-        case DISAS_SWI:
+        case DJ_SWI:
             gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
                           default_exception_el(dc));
             break;
-        case DISAS_HVC:
+        case DJ_HVC:
             gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
             break;
-        case DISAS_SMC:
+        case DJ_SMC:
             gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
             break;
         }
@@ -12140,106 +12238,16 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
         gen_set_label(dc->condlabel);
         gen_set_condexec(dc);
         if (unlikely(is_singlestepping(dc))) {
-            gen_set_pc_im(dc, dc->pc);
+            gen_set_pc_im(dc, dc->base.pc_next);
             gen_singlestep_exception(dc);
         } else {
-            gen_goto_tb(dc, 1, dc->pc);
+            gen_goto_tb(dc, 1, dc->base.pc_next);
         }
     }
-
-done_generating:
-    gen_tb_end(tb, num_insns);
-
-#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(cpu, pc_start, dc->pc - pc_start,
-                         dc->thumb | (dc->sctlr_b << 1));
-        qemu_log("\n");
-        qemu_log_unlock();
-    }
-#endif
-    tb->size = dc->pc - pc_start;
-    tb->icount = num_insns;
 }
 
-static const char *cpu_mode_names[16] = {
-  "usr", "fiq", "irq", "svc", "???", "???", "mon", "abt",
-  "???", "???", "hyp", "und", "???", "???", "???", "sys"
-};
-
-void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
-                        int flags)
+static int gen_intermediate_code_target_get_disas_flags(
+    const DisasContext *dc)
 {
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-    int i;
-    uint32_t psr;
-    const char *ns_status;
-
-    if (is_a64(env)) {
-        aarch64_cpu_dump_state(cs, f, cpu_fprintf, flags);
-        return;
-    }
-
-    for(i=0;i<16;i++) {
-        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
-        if ((i % 4) == 3)
-            cpu_fprintf(f, "\n");
-        else
-            cpu_fprintf(f, " ");
-    }
-    psr = cpsr_read(env);
-
-    if (arm_feature(env, ARM_FEATURE_EL3) &&
-        (psr & CPSR_M) != ARM_CPU_MODE_MON) {
-        ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
-    } else {
-        ns_status = "";
-    }
-
-    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
-                psr,
-                psr & (1 << 31) ? 'N' : '-',
-                psr & (1 << 30) ? 'Z' : '-',
-                psr & (1 << 29) ? 'C' : '-',
-                psr & (1 << 28) ? 'V' : '-',
-                psr & CPSR_T ? 'T' : 'A',
-                ns_status,
-                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
-
-    if (flags & CPU_DUMP_FPU) {
-        int numvfpregs = 0;
-        if (arm_feature(env, ARM_FEATURE_VFP)) {
-            numvfpregs += 16;
-        }
-        if (arm_feature(env, ARM_FEATURE_VFP3)) {
-            numvfpregs += 16;
-        }
-        for (i = 0; i < numvfpregs; i++) {
-            uint64_t v = float64_val(env->vfp.regs[i]);
-            cpu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
-                        i * 2, (uint32_t)v,
-                        i * 2 + 1, (uint32_t)(v >> 32),
-                        i, v);
-        }
-        cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
-    }
-}
-
-void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb,
-                          target_ulong *data)
-{
-    if (is_a64(env)) {
-        env->pc = data[0];
-        env->condexec_bits = 0;
-        env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT;
-    } else {
-        env->regs[15] = data[0];
-        env->condexec_bits = data[1];
-        env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT;
-    }
+    return dc->thumb | (dc->sctlr_b << 1);
 }
diff --git a/target/arm/translate.h b/target/arm/translate.h
index e42fdbe61c..5473994c37 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -1,11 +1,15 @@
 #ifndef TARGET_ARM_TRANSLATE_H
 #define TARGET_ARM_TRANSLATE_H
 
+#include "exec/translate-all_template.h"
+
+
 /* internal defines */
 typedef struct DisasContext {
-    target_ulong pc;
+    DisasContextBase base;
+
+    target_ulong next_page_start;
     uint32_t insn;
-    int is_jmp;
     /* Nonzero if this instruction has been conditionally skipped.  */
     int condjmp;
     /* The label that will be jumped to when the instruction is skipped.  */
@@ -13,8 +17,6 @@ typedef struct DisasContext {
     /* Thumb-2 conditional execution bits.  */
     int condexec_mask;
     int condexec_cond;
-    struct TranslationBlock *tb;
-    int singlestep_enabled;
     int thumb;
     int sctlr_b;
     TCGMemOp be_data;
@@ -119,39 +121,53 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
     s->insn_start_idx = 0;
 }
 
-/* target-specific extra values for is_jmp */
-/* TODO: rename as DJ_* when transitioning this target to generic translation */
+/* 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)
 /* These instructions trap after executing, so the A32/T32 decoder must
  * defer them until after the conditional execution state has been updated.
  * WFI also needs special handling when single-stepping.
  */
-#define DISAS_WFI (DISAS_TARGET + 0)
-#define DISAS_SWI (DISAS_TARGET + 1)
+#define DJ_WFI     (DJ_TARGET + 3)
+#define DJ_SWI     (DJ_TARGET + 4)
 /* For instructions which unconditionally cause an exception we can skip
  * emitting unreachable code at the end of the TB in the A64 decoder
  */
-#define DISAS_EXC (DISAS_TARGET + 2)
+#define DJ_EXC     (DJ_TARGET + 5)
 /* WFE */
-#define DISAS_WFE (DISAS_TARGET + 3)
-#define DISAS_HVC (DISAS_TARGET + 4)
-#define DISAS_SMC (DISAS_TARGET + 5)
-#define DISAS_YIELD (DISAS_TARGET + 6)
+#define DJ_WFE     (DJ_TARGET + 6)
+#define DJ_HVC     (DJ_TARGET + 7)
+#define DJ_SMC     (DJ_TARGET + 8)
+#define DJ_YIELD   (DJ_TARGET + 9)
 /* M profile branch which might be an exception return (and so needs
  * custom end-of-TB code)
  */
-#define DISAS_BX_EXCRET (DISAS_TARGET + 7)
+#define DJ_BX_EXCRET (DJ_TARGET + 10)
 /* For instructions which want an immediate exit to the main loop,
  * as opposed to attempting to use lookup_and_goto_ptr.
  */
-#define DISAS_EXIT (DISAS_TARGET + 8)
+#define DJ_EXIT (DJ_TARGET + 11)
+#define DJ_SS      (DJ_TARGET + 12)
+#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_a64_set_pc_im(uint64_t val);
 void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
                             fprintf_function cpu_fprintf, int flags);
 #else
+static inline void init_tmp_a64_array(DisasContext *s)
+{
+}
+
 static inline void a64_translate_init(void)
 {
 }

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code()
  2017-06-12 14:53 ` [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
@ 2017-06-13  1:40   ` David Gibson
  2017-06-14 21:35   ` Eduardo Habkost
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 34+ messages in thread
From: David Gibson @ 2017-06-13  1:40 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell,
	Edgar E. Iglesias, Eduardo Habkost, Michael Walle,
	Laurent Vivier, Aurelien Jarno, Yongbok Kim, Anthony Green,
	Stafford Horne, Alexander Graf, Mark Cave-Ayland,
	Artyom Tarasenko, Bastian Koppelmann, Guan Xuetao, Max Filippov,
	open list:ARM, open list:PowerPC

[-- Attachment #1: Type: text/plain, Size: 50146 bytes --]

On Mon, Jun 12, 2017 at 05:53:55PM +0300, Lluís Vilanova wrote:
> Needed to implement a target-agnostic gen_intermediate_code() in the
> future.
> 
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> Reviewed-by: Richard Henderson <rth@twiddle.net>

ppc parts

Acked-by: David Gibson <david@gibson.dropbear.id.au>

> ---
>  include/exec/exec-all.h       |    2 +-
>  target/alpha/translate.c      |   11 +++++------
>  target/arm/translate.c        |   20 ++++++++++----------
>  target/cris/translate.c       |   17 ++++++++---------
>  target/i386/translate.c       |   13 ++++++-------
>  target/lm32/translate.c       |   22 +++++++++++-----------
>  target/m68k/translate.c       |   15 +++++++--------
>  target/microblaze/translate.c |   22 +++++++++++-----------
>  target/mips/translate.c       |   15 +++++++--------
>  target/moxie/translate.c      |   14 +++++++-------
>  target/openrisc/translate.c   |   19 ++++++++++---------
>  target/ppc/translate.c        |   15 +++++++--------
>  target/s390x/translate.c      |   13 ++++++-------
>  target/sh4/translate.c        |   15 +++++++--------
>  target/sparc/translate.c      |   11 +++++------
>  target/tilegx/translate.c     |    7 +++----
>  target/tricore/translate.c    |    9 ++++-----
>  target/unicore32/translate.c  |   17 ++++++++---------
>  target/xtensa/translate.c     |   13 ++++++-------
>  translate-all.c               |    2 +-
>  20 files changed, 130 insertions(+), 142 deletions(-)
> 
> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> index 87ae10bcc9..1ec7637170 100644
> --- a/include/exec/exec-all.h
> +++ b/include/exec/exec-all.h
> @@ -43,7 +43,7 @@ typedef ram_addr_t tb_page_addr_t;
>  
>  #include "qemu/log.h"
>  
> -void gen_intermediate_code(CPUArchState *env, struct TranslationBlock *tb);
> +void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
>  void restore_state_to_opc(CPUArchState *env, struct TranslationBlock *tb,
>                            target_ulong *data);
>  
> diff --git a/target/alpha/translate.c b/target/alpha/translate.c
> index 7c45ae360c..9b60680454 100644
> --- a/target/alpha/translate.c
> +++ b/target/alpha/translate.c
> @@ -2900,10 +2900,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
>      return ret;
>  }
>  
> -void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    AlphaCPU *cpu = alpha_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUAlphaState *env = cpu->env_ptr;
>      DisasContext ctx, *ctxp = &ctx;
>      target_ulong pc_start;
>      target_ulong pc_mask;
> @@ -2918,7 +2917,7 @@ void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
>      ctx.pc = pc_start;
>      ctx.mem_idx = cpu_mmu_index(env, false);
>      ctx.implver = env->implver;
> -    ctx.singlestep_enabled = cs->singlestep_enabled;
> +    ctx.singlestep_enabled = cpu->singlestep_enabled;
>  
>  #ifdef CONFIG_USER_ONLY
>      ctx.ir = cpu_std_ir;
> @@ -2961,7 +2960,7 @@ void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(ctx.pc);
>          num_insns++;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, ctx.pc, BP_ANY))) {
>              ret = gen_excp(&ctx, EXCP_DEBUG, 0);
>              /* The address covered by the breakpoint must be included in
>                 [tb->pc, tb->pc + tb->size) in order to for it to be
> @@ -3030,7 +3029,7 @@ void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
>          && qemu_log_in_addr_range(pc_start)) {
>          qemu_log_lock();
>          qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -        log_target_disas(cs, pc_start, ctx.pc - pc_start, 1);
> +        log_target_disas(cpu, pc_start, ctx.pc - pc_start, 1);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index 0862f9e4aa..96272a9888 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -11787,10 +11787,10 @@ static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
>  }
>  
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
>  {
> -    ARMCPU *cpu = arm_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUARMState *env = cpu->env_ptr;
> +    ARMCPU *arm_cpu = arm_env_get_cpu(env);
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_start;
>      target_ulong next_page_start;
> @@ -11804,7 +11804,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
>       * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
>       */
>      if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
> -        gen_intermediate_code_a64(cpu, tb);
> +        gen_intermediate_code_a64(arm_cpu, tb);
>          return;
>      }
>  
> @@ -11814,7 +11814,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
>  
>      dc->is_jmp = DISAS_NEXT;
>      dc->pc = pc_start;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>      dc->condjmp = 0;
>  
>      dc->aarch64 = 0;
> @@ -11840,7 +11840,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
>      dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
>      dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(tb->flags);
>      dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(tb->flags);
> -    dc->cp_regs = cpu->cp_regs;
> +    dc->cp_regs = arm_cpu->cp_regs;
>      dc->features = env->features;
>  
>      /* Single step state. The code-generation logic here is:
> @@ -11941,9 +11941,9 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
>          }
>  #endif
>  
> -        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
> +        if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
>              CPUBreakpoint *bp;
> -            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
> +            QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
>                  if (bp->pc == dc->pc) {
>                      if (bp->flags & BP_CPU) {
>                          gen_set_condexec(dc);
> @@ -12042,7 +12042,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
>          if (dc->condjmp) {
>              /* FIXME:  This can theoretically happen with self-modifying
>                 code.  */
> -            cpu_abort(cs, "IO on conditional branch instruction");
> +            cpu_abort(cpu, "IO on conditional branch instruction");
>          }
>          gen_io_end();
>      }
> @@ -12156,7 +12156,7 @@ done_generating:
>          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,
> +        log_target_disas(cpu, pc_start, dc->pc - pc_start,
>                           dc->thumb | (dc->sctlr_b << 1));
>          qemu_log("\n");
>          qemu_log_unlock();
> diff --git a/target/cris/translate.c b/target/cris/translate.c
> index 0ee05ca02d..35931e7061 100644
> --- a/target/cris/translate.c
> +++ b/target/cris/translate.c
> @@ -3080,10 +3080,9 @@ static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc)
>   */
>  
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    CRISCPU *cpu = cris_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUCRISState *env = cpu->env_ptr;
>      uint32_t pc_start;
>      unsigned int insn_len;
>      struct DisasContext ctx;
> @@ -3105,13 +3104,13 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
>       * delayslot, like in real hw.
>       */
>      pc_start = tb->pc & ~1;
> -    dc->cpu = cpu;
> +    dc->cpu = cris_env_get_cpu(env);
>      dc->tb = tb;
>  
>      dc->is_jmp = DISAS_NEXT;
>      dc->ppc = pc_start;
>      dc->pc = pc_start;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>      dc->flags_uptodate = 1;
>      dc->flagx_known = 1;
>      dc->flags_x = tb->flags & X_FLAG;
> @@ -3151,7 +3150,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
>                             ? dc->ppc | 1 : dc->pc);
>          num_insns++;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              cris_evaluate_flags(dc);
>              tcg_gen_movi_tl(env_pc, dc->pc);
>              t_gen_raise_exception(EXCP_DEBUG);
> @@ -3225,7 +3224,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
>  
>          /* If we are rexecuting a branch due to exceptions on
>             delay slots don't break.  */
> -        if (!(tb->pc & 1) && cs->singlestep_enabled) {
> +        if (!(tb->pc & 1) && cpu->singlestep_enabled) {
>              break;
>          }
>      } while (!dc->is_jmp && !dc->cpustate_changed
> @@ -3258,7 +3257,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
>  
>      cris_evaluate_flags(dc);
>  
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          if (dc->is_jmp == DISAS_NEXT) {
>              tcg_gen_movi_tl(env_pc, npc);
>          }
> @@ -3293,7 +3292,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
>          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,
> +        log_target_disas(cpu, pc_start, dc->pc - pc_start,
>                           env->pregs[PR_VR]);
>          qemu_log("\nisize=%d osize=%d\n",
>                   dc->pc - pc_start, tcg_op_buf_count());
> diff --git a/target/i386/translate.c b/target/i386/translate.c
> index 674ec96d5a..b38bcabfc2 100644
> --- a/target/i386/translate.c
> +++ b/target/i386/translate.c
> @@ -8366,10 +8366,9 @@ void tcg_x86_init(void)
>  }
>  
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
>  {
> -    X86CPU *cpu = x86_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUX86State *env = cpu->env_ptr;
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_ptr;
>      uint32_t flags;
> @@ -8392,7 +8391,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
>      dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
>      dc->iopl = (flags >> IOPL_SHIFT) & 3;
>      dc->tf = (flags >> TF_SHIFT) & 1;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>      dc->cc_op = CC_OP_DYNAMIC;
>      dc->cc_op_dirty = false;
>      dc->cs_base = cs_base;
> @@ -8414,7 +8413,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
>      dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
>  #endif
>      dc->flags = flags;
> -    dc->jmp_opt = !(dc->tf || cs->singlestep_enabled ||
> +    dc->jmp_opt = !(dc->tf || cpu->singlestep_enabled ||
>                      (flags & HF_INHIBIT_IRQ_MASK));
>      /* Do not optimize repz jumps at all in icount mode, because
>         rep movsS instructions are execured with different paths
> @@ -8463,7 +8462,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
>          num_insns++;
>  
>          /* If RF is set, suppress an internally generated breakpoint.  */
> -        if (unlikely(cpu_breakpoint_test(cs, pc_ptr,
> +        if (unlikely(cpu_breakpoint_test(cpu, pc_ptr,
>                                           tb->flags & HF_RF_MASK
>                                           ? BP_GDB : BP_ANY))) {
>              gen_debug(dc, pc_ptr - dc->cs_base);
> @@ -8539,7 +8538,7 @@ done_generating:
>          else
>  #endif
>              disas_flags = !dc->code32;
> -        log_target_disas(cs, pc_start, pc_ptr - pc_start, disas_flags);
> +        log_target_disas(cpu, pc_start, pc_ptr - pc_start, disas_flags);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/lm32/translate.c b/target/lm32/translate.c
> index 692882f447..0ac34fc620 100644
> --- a/target/lm32/translate.c
> +++ b/target/lm32/translate.c
> @@ -1044,10 +1044,10 @@ static inline void decode(DisasContext *dc, uint32_t ir)
>  }
>  
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    LM32CPU *cpu = lm32_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPULM32State *env = cpu->env_ptr;
> +    LM32CPU *lm32_cpu = lm32_env_get_cpu(env);
>      struct DisasContext ctx, *dc = &ctx;
>      uint32_t pc_start;
>      uint32_t next_page_start;
> @@ -1055,14 +1055,14 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
>      int max_insns;
>  
>      pc_start = tb->pc;
> -    dc->features = cpu->features;
> -    dc->num_breakpoints = cpu->num_breakpoints;
> -    dc->num_watchpoints = cpu->num_watchpoints;
> +    dc->features = lm32_cpu->features;
> +    dc->num_breakpoints = lm32_cpu->num_breakpoints;
> +    dc->num_watchpoints = lm32_cpu->num_watchpoints;
>      dc->tb = tb;
>  
>      dc->is_jmp = DISAS_NEXT;
>      dc->pc = pc_start;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>  
>      if (pc_start & 3) {
>          qemu_log_mask(LOG_GUEST_ERROR,
> @@ -1085,7 +1085,7 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(dc->pc);
>          num_insns++;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              tcg_gen_movi_tl(cpu_pc, dc->pc);
>              t_gen_raise_exception(dc, EXCP_DEBUG);
>              dc->is_jmp = DISAS_UPDATE;
> @@ -1108,7 +1108,7 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
>          dc->pc += 4;
>      } while (!dc->is_jmp
>           && !tcg_op_buf_full()
> -         && !cs->singlestep_enabled
> +         && !cpu->singlestep_enabled
>           && !singlestep
>           && (dc->pc < next_page_start)
>           && num_insns < max_insns);
> @@ -1117,7 +1117,7 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
>          gen_io_end();
>      }
>  
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          if (dc->is_jmp == DISAS_NEXT) {
>              tcg_gen_movi_tl(cpu_pc, dc->pc);
>          }
> @@ -1150,7 +1150,7 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
>          && qemu_log_in_addr_range(pc_start)) {
>          qemu_log_lock();
>          qemu_log("\n");
> -        log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
> +        log_target_disas(cpu, pc_start, dc->pc - pc_start, 0);
>          qemu_log("\nisize=%d osize=%d\n",
>                   dc->pc - pc_start, tcg_op_buf_count());
>          qemu_log_unlock();
> diff --git a/target/m68k/translate.c b/target/m68k/translate.c
> index ad4d4efb8d..0a3372818c 100644
> --- a/target/m68k/translate.c
> +++ b/target/m68k/translate.c
> @@ -5039,10 +5039,9 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
>  }
>  
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
>  {
> -    M68kCPU *cpu = m68k_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUM68KState *env = cpu->env_ptr;
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_start;
>      int pc_offset;
> @@ -5059,7 +5058,7 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
>      dc->pc = pc_start;
>      dc->cc_op = CC_OP_DYNAMIC;
>      dc->cc_op_synced = 1;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>      dc->fpcr = env->fpcr;
>      dc->user = (env->sr & SR_S) == 0;
>      dc->done_mac = 0;
> @@ -5080,7 +5079,7 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
>          tcg_gen_insn_start(dc->pc, dc->cc_op);
>          num_insns++;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              gen_exception(dc, dc->pc, EXCP_DEBUG);
>              dc->is_jmp = DISAS_JUMP;
>              /* The address covered by the breakpoint must be included in
> @@ -5098,14 +5097,14 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
>          dc->insn_pc = dc->pc;
>  	disas_m68k_insn(env, dc);
>      } while (!dc->is_jmp && !tcg_op_buf_full() &&
> -             !cs->singlestep_enabled &&
> +             !cpu->singlestep_enabled &&
>               !singlestep &&
>               (pc_offset) < (TARGET_PAGE_SIZE - 32) &&
>               num_insns < max_insns);
>  
>      if (tb->cflags & CF_LAST_IO)
>          gen_io_end();
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          /* Make sure the pc is updated, and raise a debug exception.  */
>          if (!dc->is_jmp) {
>              update_cc_op(dc);
> @@ -5138,7 +5137,7 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
>          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, 0);
> +        log_target_disas(cpu, pc_start, dc->pc - pc_start, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
> index 0bb609513c..d5f499658d 100644
> --- a/target/microblaze/translate.c
> +++ b/target/microblaze/translate.c
> @@ -1594,10 +1594,10 @@ static inline void decode(DisasContext *dc, uint32_t ir)
>  }
>  
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    MicroBlazeCPU *cpu = mb_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUMBState *env = cpu->env_ptr;
> +    MicroBlazeCPU *mb_cpu = mb_env_get_cpu(env);
>      uint32_t pc_start;
>      struct DisasContext ctx;
>      struct DisasContext *dc = &ctx;
> @@ -1607,7 +1607,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>      int max_insns;
>  
>      pc_start = tb->pc;
> -    dc->cpu = cpu;
> +    dc->cpu = mb_cpu;
>      dc->tb = tb;
>      org_flags = dc->synced_flags = dc->tb_flags = tb->flags;
>  
> @@ -1618,13 +1618,13 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>          dc->jmp = JMP_INDIRECT;
>      }
>      dc->pc = pc_start;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>      dc->cpustate_changed = 0;
>      dc->abort_at_next_insn = 0;
>      dc->nr_nops = 0;
>  
>      if (pc_start & 3) {
> -        cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start);
> +        cpu_abort(cpu, "Microblaze: unaligned PC=%x\n", pc_start);
>      }
>  
>      next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
> @@ -1650,7 +1650,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>          }
>  #endif
>  
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              t_gen_raise_exception(dc, EXCP_DEBUG);
>              dc->is_jmp = DISAS_UPDATE;
>              /* The address covered by the breakpoint must be included in
> @@ -1707,7 +1707,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>                  break;
>              }
>          }
> -        if (cs->singlestep_enabled) {
> +        if (cpu->singlestep_enabled) {
>              break;
>          }
>      } while (!dc->is_jmp && !dc->cpustate_changed
> @@ -1728,7 +1728,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>  
>      if (tb->cflags & CF_LAST_IO)
>          gen_io_end();
> -    /* Force an update if the per-tb cpu state has changed.  */
> +    /* Force an update if the per-tb mb_cpu state has changed.  */
>      if (dc->is_jmp == DISAS_NEXT
>          && (dc->cpustate_changed || org_flags != dc->tb_flags)) {
>          dc->is_jmp = DISAS_UPDATE;
> @@ -1736,7 +1736,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>      }
>      t_sync_flags(dc);
>  
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
>  
>          if (dc->is_jmp != DISAS_JUMP) {
> @@ -1773,7 +1773,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>          qemu_log_lock();
>          qemu_log("--------------\n");
>  #if DISAS_GNU
> -        log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
> +        log_target_disas(cpu, pc_start, dc->pc - pc_start, 0);
>  #endif
>          qemu_log("\nisize=%d osize=%d\n",
>                   dc->pc - pc_start, tcg_op_buf_count());
> diff --git a/target/mips/translate.c b/target/mips/translate.c
> index 559f8fed89..1f9e02f426 100644
> --- a/target/mips/translate.c
> +++ b/target/mips/translate.c
> @@ -19878,10 +19878,9 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
>      }
>  }
>  
> -void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    MIPSCPU *cpu = mips_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUMIPSState *env = cpu->env_ptr;
>      DisasContext ctx;
>      target_ulong pc_start;
>      target_ulong next_page_start;
> @@ -19894,7 +19893,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
>      next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>      ctx.pc = pc_start;
>      ctx.saved_pc = -1;
> -    ctx.singlestep_enabled = cs->singlestep_enabled;
> +    ctx.singlestep_enabled = cpu->singlestep_enabled;
>      ctx.insn_flags = env->insn_flags;
>      ctx.CP0_Config1 = env->CP0_Config1;
>      ctx.tb = tb;
> @@ -19941,7 +19940,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(ctx.pc, ctx.hflags & MIPS_HFLAG_BMASK, ctx.btarget);
>          num_insns++;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, ctx.pc, BP_ANY))) {
>              save_cpu_state(&ctx, 1);
>              ctx.bstate = BS_BRANCH;
>              gen_helper_raise_exception_debug(cpu_env);
> @@ -19996,7 +19995,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
>             This is what GDB expects and is consistent with what the
>             hardware does (e.g. if a delay slot instruction faults, the
>             reported PC is the PC of the branch).  */
> -        if (cs->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0) {
> +        if (cpu->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0) {
>              break;
>          }
>  
> @@ -20017,7 +20016,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
>      if (tb->cflags & CF_LAST_IO) {
>          gen_io_end();
>      }
> -    if (cs->singlestep_enabled && ctx.bstate != BS_BRANCH) {
> +    if (cpu->singlestep_enabled && ctx.bstate != BS_BRANCH) {
>          save_cpu_state(&ctx, ctx.bstate != BS_EXCP);
>          gen_helper_raise_exception_debug(cpu_env);
>      } else {
> @@ -20049,7 +20048,7 @@ done_generating:
>          && qemu_log_in_addr_range(pc_start)) {
>          qemu_log_lock();
>          qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -        log_target_disas(cs, pc_start, ctx.pc - pc_start, 0);
> +        log_target_disas(cpu, pc_start, ctx.pc - pc_start, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/moxie/translate.c b/target/moxie/translate.c
> index 0660b44c08..176063a1de 100644
> --- a/target/moxie/translate.c
> +++ b/target/moxie/translate.c
> @@ -822,10 +822,10 @@ static int decode_opc(MoxieCPU *cpu, DisasContext *ctx)
>  }
>  
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    MoxieCPU *cpu = moxie_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUMoxieState *env = cpu->env_ptr;
> +    MoxieCPU *moxie_cpu = moxie_env_get_cpu(env);
>      DisasContext ctx;
>      target_ulong pc_start;
>      int num_insns, max_insns;
> @@ -851,7 +851,7 @@ void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(ctx.pc);
>          num_insns++;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, ctx.pc, BP_ANY))) {
>              tcg_gen_movi_i32(cpu_pc, ctx.pc);
>              gen_helper_debug(cpu_env);
>              ctx.bstate = BS_EXCP;
> @@ -864,12 +864,12 @@ void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
>          }
>  
>          ctx.opcode = cpu_lduw_code(env, ctx.pc);
> -        ctx.pc += decode_opc(cpu, &ctx);
> +        ctx.pc += decode_opc(moxie_cpu, &ctx);
>  
>          if (num_insns >= max_insns) {
>              break;
>          }
> -        if (cs->singlestep_enabled) {
> +        if (cpu->singlestep_enabled) {
>              break;
>          }
>          if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) {
> @@ -877,7 +877,7 @@ void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
>          }
>      } while (ctx.bstate == BS_NONE && !tcg_op_buf_full());
>  
> -    if (cs->singlestep_enabled) {
> +    if (cpu->singlestep_enabled) {
>          tcg_gen_movi_tl(cpu_pc, ctx.pc);
>          gen_helper_debug(cpu_env);
>      } else {
> diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
> index e49518e893..aaac359d5b 100644
> --- a/target/openrisc/translate.c
> +++ b/target/openrisc/translate.c
> @@ -1518,9 +1518,10 @@ static void disas_openrisc_insn(DisasContext *dc, OpenRISCCPU *cpu)
>      }
>  }
>  
> -void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
> +    OpenRISCState *env = cpu->env_ptr;
> +    OpenRISCCPU *or_cpu = openrisc_env_get_cpu(env);
>      CPUState *cs = CPU(cpu);
>      struct DisasContext ctx, *dc = &ctx;
>      uint32_t pc_start;
> @@ -1533,10 +1534,10 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
>  
>      dc->is_jmp = DISAS_NEXT;
>      dc->pc = pc_start;
> -    dc->mem_idx = cpu_mmu_index(&cpu->env, false);
> +    dc->mem_idx = cpu_mmu_index(&or_cpu->env, false);
>      dc->tb_flags = tb->flags;
>      dc->delayed_branch = (dc->tb_flags & TB_FLAGS_DFLAG) != 0;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>  
>      next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>      num_insns = 0;
> @@ -1571,7 +1572,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
>  			   | (num_insns ? 2 : 0));
>          num_insns++;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              tcg_gen_movi_tl(cpu_pc, dc->pc);
>              gen_exception(dc, EXCP_DEBUG);
>              dc->is_jmp = DISAS_UPDATE;
> @@ -1586,7 +1587,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
>          if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
>              gen_io_start();
>          }
> -        disas_openrisc_insn(dc, cpu);
> +        disas_openrisc_insn(dc, or_cpu);
>          dc->pc = dc->pc + 4;
>  
>          /* delay slot */
> @@ -1601,7 +1602,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
>          }
>      } while (!dc->is_jmp
>               && !tcg_op_buf_full()
> -             && !cs->singlestep_enabled
> +             && !cpu->singlestep_enabled
>               && !singlestep
>               && (dc->pc < next_page_start)
>               && num_insns < max_insns);
> @@ -1619,7 +1620,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
>          dc->is_jmp = DISAS_UPDATE;
>          tcg_gen_movi_tl(cpu_pc, dc->pc);
>      }
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          gen_exception(dc, EXCP_DEBUG);
>      } else {
>          switch (dc->is_jmp) {
> @@ -1647,7 +1648,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
>  
>      if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
>          && qemu_log_in_addr_range(pc_start)) {
> -        log_target_disas(cs, pc_start, tb->size, 0);
> +        log_target_disas(cpu, pc_start, tb->size, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index c0cd64d927..9a934117d8 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -7203,10 +7203,9 @@ void ppc_cpu_dump_statistics(CPUState *cs, FILE*f,
>  }
>  
>  /*****************************************************************************/
> -void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    PowerPCCPU *cpu = ppc_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = cpu->env_ptr;
>      DisasContext ctx, *ctxp = &ctx;
>      opc_handler_t **table, *handler;
>      target_ulong pc_start;
> @@ -7267,7 +7266,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
>          ctx.singlestep_enabled = 0;
>      if ((env->flags & POWERPC_FLAG_BE) && msr_be)
>          ctx.singlestep_enabled |= CPU_BRANCH_STEP;
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP;
>      }
>  #if defined (DO_SINGLE_STEP) && 0
> @@ -7290,7 +7289,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(ctx.nip);
>          num_insns++;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, ctx.nip, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, ctx.nip, BP_ANY))) {
>              gen_debug_exception(ctxp);
>              /* The address covered by the breakpoint must be included in
>                 [tb->pc, tb->pc + tb->size) in order to for it to be
> @@ -7369,7 +7368,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
>                       ctx.exception != POWERPC_EXCP_BRANCH)) {
>              gen_exception_nip(ctxp, POWERPC_EXCP_TRACE, ctx.nip);
>          } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
> -                            (cs->singlestep_enabled) ||
> +                            (cpu->singlestep_enabled) ||
>                              singlestep ||
>                              num_insns >= max_insns)) {
>              /* if we reach a page boundary or are single stepping, stop
> @@ -7389,7 +7388,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
>      if (ctx.exception == POWERPC_EXCP_NONE) {
>          gen_goto_tb(&ctx, 0, ctx.nip);
>      } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
> -        if (unlikely(cs->singlestep_enabled)) {
> +        if (unlikely(cpu->singlestep_enabled)) {
>              gen_debug_exception(ctxp);
>          }
>          /* Generate the return instruction */
> @@ -7408,7 +7407,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
>          flags |= ctx.le_mode << 16;
>          qemu_log_lock();
>          qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -        log_target_disas(cs, pc_start, ctx.nip - pc_start, flags);
> +        log_target_disas(cpu, pc_start, ctx.nip - pc_start, flags);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/s390x/translate.c b/target/s390x/translate.c
> index 95f91d4f08..2a17b3d7aa 100644
> --- a/target/s390x/translate.c
> +++ b/target/s390x/translate.c
> @@ -5714,10 +5714,9 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s)
>      return ret;
>  }
>  
> -void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    S390CPU *cpu = s390_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUS390XState *env = cpu->env_ptr;
>      DisasContext dc;
>      target_ulong pc_start;
>      uint64_t next_page_start;
> @@ -5736,7 +5735,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
>      dc.pc = pc_start;
>      dc.cc_op = CC_OP_DYNAMIC;
>      dc.ex_value = tb->cs_base;
> -    do_debug = dc.singlestep_enabled = cs->singlestep_enabled;
> +    do_debug = dc.singlestep_enabled = cpu->singlestep_enabled;
>  
>      next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>  
> @@ -5755,7 +5754,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(dc.pc, dc.cc_op);
>          num_insns++;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, dc.pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc.pc, BP_ANY))) {
>              status = EXIT_PC_STALE;
>              do_debug = true;
>              /* The address covered by the breakpoint must be included in
> @@ -5779,7 +5778,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
>                  || tcg_op_buf_full()
>                  || num_insns >= max_insns
>                  || singlestep
> -                || cs->singlestep_enabled
> +                || cpu->singlestep_enabled
>                  || dc.ex_value)) {
>              status = EXIT_PC_STALE;
>          }
> @@ -5829,7 +5828,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
>              qemu_log("IN: EXECUTE %016" PRIx64 "\n", dc.ex_value);
>          } else {
>              qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -            log_target_disas(cs, pc_start, dc.pc - pc_start, 1);
> +            log_target_disas(cpu, pc_start, dc.pc - pc_start, 1);
>              qemu_log("\n");
>          }
>          qemu_log_unlock();
> diff --git a/target/sh4/translate.c b/target/sh4/translate.c
> index 8bc132b27b..6a797072d4 100644
> --- a/target/sh4/translate.c
> +++ b/target/sh4/translate.c
> @@ -1815,10 +1815,9 @@ static void decode_opc(DisasContext * ctx)
>      }
>  }
>  
> -void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    SuperHCPU *cpu = sh_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUSH4State *env = cpu->env_ptr;
>      DisasContext ctx;
>      target_ulong pc_start;
>      int num_insns;
> @@ -1834,7 +1833,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
>         so assume it is a dynamic branch.  */
>      ctx.delayed_pc = -1; /* use delayed pc from env pointer */
>      ctx.tb = tb;
> -    ctx.singlestep_enabled = cs->singlestep_enabled;
> +    ctx.singlestep_enabled = cpu->singlestep_enabled;
>      ctx.features = env->features;
>      ctx.has_movcal = (ctx.tbflags & TB_FLAG_PENDING_MOVCA);
>  
> @@ -1852,7 +1851,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(ctx.pc, ctx.envflags);
>          num_insns++;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, ctx.pc, BP_ANY))) {
>              /* We have hit a breakpoint - make sure PC is up-to-date */
>              gen_save_cpu_state(&ctx, true);
>              gen_helper_debug(cpu_env);
> @@ -1874,7 +1873,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
>  	ctx.pc += 2;
>  	if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
>  	    break;
> -        if (cs->singlestep_enabled) {
> +        if (cpu->singlestep_enabled) {
>  	    break;
>          }
>          if (num_insns >= max_insns)
> @@ -1884,7 +1883,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
>      }
>      if (tb->cflags & CF_LAST_IO)
>          gen_io_end();
> -    if (cs->singlestep_enabled) {
> +    if (cpu->singlestep_enabled) {
>          gen_save_cpu_state(&ctx, true);
>          gen_helper_debug(cpu_env);
>      } else {
> @@ -1915,7 +1914,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
>          && qemu_log_in_addr_range(pc_start)) {
>          qemu_log_lock();
>  	qemu_log("IN:\n");	/* , lookup_symbol(pc_start)); */
> -        log_target_disas(cs, pc_start, ctx.pc - pc_start, 0);
> +        log_target_disas(cpu, pc_start, ctx.pc - pc_start, 0);
>  	qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/sparc/translate.c b/target/sparc/translate.c
> index aa6734d54e..90c43e4460 100644
> --- a/target/sparc/translate.c
> +++ b/target/sparc/translate.c
> @@ -5747,10 +5747,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
>      }
>  }
>  
> -void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
> +void gen_intermediate_code(CPUState *cpu, TranslationBlock * tb)
>  {
> -    SPARCCPU *cpu = sparc_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUSPARCState *env = cpu->env_ptr;
>      target_ulong pc_start, last_pc;
>      DisasContext dc1, *dc = &dc1;
>      int num_insns;
> @@ -5768,7 +5767,7 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
>      dc->def = env->def;
>      dc->fpu_enabled = tb_fpu_enabled(tb->flags);
>      dc->address_mask_32bit = tb_am_enabled(tb->flags);
> -    dc->singlestep = (cs->singlestep_enabled || singlestep);
> +    dc->singlestep = (cpu->singlestep_enabled || singlestep);
>  #ifndef CONFIG_USER_ONLY
>      dc->supervisor = (tb->flags & TB_FLAG_SUPER) != 0;
>  #endif
> @@ -5800,7 +5799,7 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
>          num_insns++;
>          last_pc = dc->pc;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              if (dc->pc != pc_start) {
>                  save_state(dc);
>              }
> @@ -5864,7 +5863,7 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
>          qemu_log_lock();
>          qemu_log("--------------\n");
>          qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -        log_target_disas(cs, pc_start, last_pc + 4 - pc_start, 0);
> +        log_target_disas(cpu, pc_start, last_pc + 4 - pc_start, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/tilegx/translate.c b/target/tilegx/translate.c
> index ff2ef7b63d..a86e9e9d22 100644
> --- a/target/tilegx/translate.c
> +++ b/target/tilegx/translate.c
> @@ -2370,12 +2370,11 @@ static void translate_one_bundle(DisasContext *dc, uint64_t bundle)
>      }
>  }
>  
> -void gen_intermediate_code(CPUTLGState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    TileGXCPU *cpu = tilegx_env_get_cpu(env);
> +    CPUTLGState *env = cpu->env_ptr;
>      DisasContext ctx;
>      DisasContext *dc = &ctx;
> -    CPUState *cs = CPU(cpu);
>      uint64_t pc_start = tb->pc;
>      uint64_t next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>      int num_insns = 0;
> @@ -2397,7 +2396,7 @@ void gen_intermediate_code(CPUTLGState *env, struct TranslationBlock *tb)
>      if (!max_insns) {
>          max_insns = CF_COUNT_MASK;
>      }
> -    if (cs->singlestep_enabled || singlestep) {
> +    if (cpu->singlestep_enabled || singlestep) {
>          max_insns = 1;
>      }
>      if (max_insns > TCG_MAX_INSNS) {
> diff --git a/target/tricore/translate.c b/target/tricore/translate.c
> index ddd2dd07dd..1930da2f2a 100644
> --- a/target/tricore/translate.c
> +++ b/target/tricore/translate.c
> @@ -8782,10 +8782,9 @@ static void decode_opc(CPUTriCoreState *env, DisasContext *ctx, int *is_branch)
>      }
>  }
>  
> -void gen_intermediate_code(CPUTriCoreState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    TriCoreCPU *cpu = tricore_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUTriCoreState *env = cpu->env_ptr;
>      DisasContext ctx;
>      target_ulong pc_start;
>      int num_insns, max_insns;
> @@ -8806,7 +8805,7 @@ void gen_intermediate_code(CPUTriCoreState *env, struct TranslationBlock *tb)
>      ctx.pc = pc_start;
>      ctx.saved_pc = -1;
>      ctx.tb = tb;
> -    ctx.singlestep_enabled = cs->singlestep_enabled;
> +    ctx.singlestep_enabled = cpu->singlestep_enabled;
>      ctx.bstate = BS_NONE;
>      ctx.mem_idx = cpu_mmu_index(env, false);
>  
> @@ -8840,7 +8839,7 @@ void gen_intermediate_code(CPUTriCoreState *env, struct TranslationBlock *tb)
>          && qemu_log_in_addr_range(pc_start)) {
>          qemu_log_lock();
>          qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -        log_target_disas(cs, pc_start, ctx.pc - pc_start, 0);
> +        log_target_disas(cpu, pc_start, ctx.pc - pc_start, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c
> index 666a2016a8..494ed58c10 100644
> --- a/target/unicore32/translate.c
> +++ b/target/unicore32/translate.c
> @@ -1869,10 +1869,9 @@ static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s)
>  }
>  
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
>  {
> -    UniCore32CPU *cpu = uc32_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUUniCore32State *env = cpu->env_ptr;
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_start;
>      uint32_t next_page_start;
> @@ -1888,7 +1887,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
>  
>      dc->is_jmp = DISAS_NEXT;
>      dc->pc = pc_start;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>      dc->condjmp = 0;
>      cpu_F0s = tcg_temp_new_i32();
>      cpu_F1s = tcg_temp_new_i32();
> @@ -1917,7 +1916,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
>          tcg_gen_insn_start(dc->pc);
>          num_insns++;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              gen_set_pc_im(dc->pc);
>              gen_exception(EXCP_DEBUG);
>              dc->is_jmp = DISAS_JUMP;
> @@ -1949,7 +1948,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
>           * Also stop translation when a page boundary is reached.  This
>           * ensures prefetch aborts occur at the right place.  */
>      } while (!dc->is_jmp && !tcg_op_buf_full() &&
> -             !cs->singlestep_enabled &&
> +             !cpu->singlestep_enabled &&
>               !singlestep &&
>               dc->pc < next_page_start &&
>               num_insns < max_insns);
> @@ -1958,7 +1957,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
>          if (dc->condjmp) {
>              /* FIXME:  This can theoretically happen with self-modifying
>                 code.  */
> -            cpu_abort(cs, "IO on conditional branch instruction");
> +            cpu_abort(cpu, "IO on conditional branch instruction");
>          }
>          gen_io_end();
>      }
> @@ -1966,7 +1965,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
>      /* At this stage dc->condjmp will only be set when the skipped
>         instruction was a conditional branch or trap, and the PC has
>         already been written.  */
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          /* Make sure the pc is updated, and raise a debug exception.  */
>          if (dc->condjmp) {
>              if (dc->is_jmp == DISAS_SYSCALL) {
> @@ -2027,7 +2026,7 @@ done_generating:
>          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, 0);
> +        log_target_disas(cpu, pc_start, dc->pc - pc_start, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
> index 263002486c..63e4f25c08 100644
> --- a/target/xtensa/translate.c
> +++ b/target/xtensa/translate.c
> @@ -3117,10 +3117,9 @@ static void gen_ibreak_check(CPUXtensaState *env, DisasContext *dc)
>      }
>  }
>  
> -void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
>  {
> -    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUXtensaState *env = cpu->env_ptr;
>      DisasContext dc;
>      int insn_count = 0;
>      int max_insns = tb->cflags & CF_COUNT_MASK;
> @@ -3136,7 +3135,7 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
>      }
>  
>      dc.config = env->config;
> -    dc.singlestep_enabled = cs->singlestep_enabled;
> +    dc.singlestep_enabled = cpu->singlestep_enabled;
>      dc.tb = tb;
>      dc.pc = pc_start;
>      dc.ring = tb->flags & XTENSA_TBFLAG_RING_MASK;
> @@ -3179,7 +3178,7 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
>          tcg_gen_insn_start(dc.pc);
>          ++insn_count;
>  
> -        if (unlikely(cpu_breakpoint_test(cs, dc.pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc.pc, BP_ANY))) {
>              tcg_gen_movi_i32(cpu_pc, dc.pc);
>              gen_exception(&dc, EXCP_DEBUG);
>              dc.is_jmp = DISAS_UPDATE;
> @@ -3215,7 +3214,7 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
>          if (dc.icount) {
>              tcg_gen_mov_i32(cpu_SR[ICOUNT], dc.next_icount);
>          }
> -        if (cs->singlestep_enabled) {
> +        if (cpu->singlestep_enabled) {
>              tcg_gen_movi_i32(cpu_pc, dc.pc);
>              gen_exception(&dc, EXCP_DEBUG);
>              break;
> @@ -3247,7 +3246,7 @@ done:
>          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, 0);
> +        log_target_disas(cpu, pc_start, dc.pc - pc_start, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/translate-all.c b/translate-all.c
> index b3ee876526..e5de5cace9 100644
> --- a/translate-all.c
> +++ b/translate-all.c
> @@ -1292,7 +1292,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
>      tcg_func_start(&tcg_ctx);
>  
>      tcg_ctx.cpu = ENV_GET_CPU(env);
> -    gen_intermediate_code(env, tb);
> +    gen_intermediate_code(cpu, tb);
>      tcg_ctx.cpu = NULL;
>  
>      trace_translate_block(tb, tb->pc, tb->tc_ptr);
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code()
  2017-06-12 14:53 ` [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
  2017-06-13  1:40   ` David Gibson
@ 2017-06-14 21:35   ` Eduardo Habkost
  2017-06-14 22:30   ` Laurent Vivier
  2017-06-16 14:07   ` Alex Bennée
  3 siblings, 0 replies; 34+ messages in thread
From: Eduardo Habkost @ 2017-06-14 21:35 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell,
	Edgar E. Iglesias, Michael Walle, Laurent Vivier, Aurelien Jarno,
	Yongbok Kim, Anthony Green, Stafford Horne, David Gibson,
	Alexander Graf, Mark Cave-Ayland, Artyom Tarasenko,
	Bastian Koppelmann, Guan Xuetao, Max Filippov, open list:ARM,
	open list:PowerPC

On Mon, Jun 12, 2017 at 05:53:55PM +0300, Lluís Vilanova wrote:
> Needed to implement a target-agnostic gen_intermediate_code() in the
> future.
> 
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> Reviewed-by: Richard Henderson <rth@twiddle.net>

Acked-by: Eduardo Habkost <ehabkost@redhat.com>

For i386 parts:

Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>

-- 
Eduardo

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code()
  2017-06-12 14:53 ` [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
  2017-06-13  1:40   ` David Gibson
  2017-06-14 21:35   ` Eduardo Habkost
@ 2017-06-14 22:30   ` Laurent Vivier
  2017-06-16 14:07   ` Alex Bennée
  3 siblings, 0 replies; 34+ messages in thread
From: Laurent Vivier @ 2017-06-14 22:30 UTC (permalink / raw)
  To: Lluís Vilanova, qemu-devel
  Cc: Peter Maydell, Anthony Green, Mark Cave-Ayland, Max Filippov,
	Edgar E. Iglesias, Guan Xuetao, Alexander Graf,
	Richard Henderson, Artyom Tarasenko, Eduardo Habkost,
	open list:ARM, Yongbok Kim, Stafford Horne, Alex Bennée,
	David Gibson, Peter Crosthwaite, Bastian Koppelmann,
	Michael Walle, open list:PowerPC, Paolo Bonzini, Aurelien Jarno

Le 12/06/2017 à 16:53, Lluís Vilanova a écrit :
> Needed to implement a target-agnostic gen_intermediate_code() in the
> future.
> 
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> Reviewed-by: Richard Henderson <rth@twiddle.net>
> ---
>  include/exec/exec-all.h       |    2 +-
>  target/alpha/translate.c      |   11 +++++------
>  target/arm/translate.c        |   20 ++++++++++----------
>  target/cris/translate.c       |   17 ++++++++---------
>  target/i386/translate.c       |   13 ++++++-------
>  target/lm32/translate.c       |   22 +++++++++++-----------
>  target/m68k/translate.c       |   15 +++++++--------
>  target/microblaze/translate.c |   22 +++++++++++-----------
>  target/mips/translate.c       |   15 +++++++--------
>  target/moxie/translate.c      |   14 +++++++-------
>  target/openrisc/translate.c   |   19 ++++++++++---------
>  target/ppc/translate.c        |   15 +++++++--------
>  target/s390x/translate.c      |   13 ++++++-------
>  target/sh4/translate.c        |   15 +++++++--------
>  target/sparc/translate.c      |   11 +++++------
>  target/tilegx/translate.c     |    7 +++----
>  target/tricore/translate.c    |    9 ++++-----
>  target/unicore32/translate.c  |   17 ++++++++---------
>  target/xtensa/translate.c     |   13 ++++++-------
>  translate-all.c               |    2 +-
>  20 files changed, 130 insertions(+), 142 deletions(-)

for m68k part:

Acked-by: Laurent Vivier <laurent@vivier.eu>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic translation framework
  2017-06-12 14:53 [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (4 preceding siblings ...)
  2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 6/6] target: [tcg, arm] Port to generic translation framework Lluís Vilanova
@ 2017-06-15 18:02 ` Emilio G. Cota
  2017-06-18 14:41   ` Lluís Vilanova
  5 siblings, 1 reply; 34+ messages in thread
From: Emilio G. Cota @ 2017-06-15 18:02 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Paolo Bonzini, Peter Crosthwaite, Alex Bennée,
	Richard Henderson

On Mon, Jun 12, 2017 at 17:53:47 +0300, Lluís Vilanova wrote:
> This series proposes a generic (target-agnostic) instruction translation
> framework.
> 
> It basically provides a generic main loop for instruction disassembly, which
> calls target-specific functions when necessary. This generalization makes
> inserting new code in the main loop easier, and helps in keeping all targets in
> synch as to the contents of it.
> 
> This series also paves the way towards adding events to trace guest code
> execution (BBLs and instructions).
> 
> I've ported i386/x86-64 and arm/aarch64 as an example to see how it fits in the
> current organization, but will port the rest when this series gets merged.

It seems patch 5 didn't make it through the list (the list drops patches
sometimes):
  https://lists.gnu.org/archive/html/qemu-devel/2017-06/msg02833.html

I think I've found it in your qemu-dbi tree though (1c97cf92b06).
I pasted it here: https://pastebin.ca/3832616

		E.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [Qemu-devel] [PATCH] translator mega-patch
  2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework Lluís Vilanova
@ 2017-06-15 22:05   ` Emilio G. Cota
  2017-06-18 14:37     ` Lluís Vilanova
  2017-06-15 22:19   ` [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework Emilio G. Cota
  1 sibling, 1 reply; 34+ messages in thread
From: Emilio G. Cota @ 2017-06-15 22:05 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Paolo Bonzini, Peter Crosthwaite, Alex Bennée,
	Richard Henderson

On Mon, Jun 12, 2017 at 17:54:09 +0300, Lluís Vilanova wrote:
> Signed-off-by: Lluís Vilanova <vilanova@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; 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 <cota@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

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework
  2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework Lluís Vilanova
  2017-06-15 22:05   ` [Qemu-devel] [PATCH] translator mega-patch Emilio G. Cota
@ 2017-06-15 22:19   ` Emilio G. Cota
  2017-06-15 23:25     ` Emilio G. Cota
  2017-06-18 14:20     ` Lluís Vilanova
  1 sibling, 2 replies; 34+ messages in thread
From: Emilio G. Cota @ 2017-06-15 22:19 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Paolo Bonzini, Peter Crosthwaite, Alex Bennée,
	Richard Henderson

Some minor nits below.

On Mon, Jun 12, 2017 at 17:54:09 +0300, Lluís Vilanova wrote:
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> ---
> +/**
> + * 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;

BH_MISS reads out loud to "Breakpoint Hit Miss"; that's quite counterintuitive.
Similarly for the others (e.g. "breakpoint Hit Hit -- ??".

Can we just do BP_{MISS,HIT,etc}? Thinking about it, perhaps BP_NONE is
better than BP_MISS.

(snip)
> +/**
> + * 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;

- @pc_next: I'd stick with @pc, it's shorter, it's everywhere already, and
  with the documentation it's very clear what it is for.
- @jmp_type: missing doc :-)

Thanks,

		E.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework
  2017-06-15 22:19   ` [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework Emilio G. Cota
@ 2017-06-15 23:25     ` Emilio G. Cota
  2017-06-17  1:09       ` Emilio G. Cota
  2017-06-18 14:22       ` Lluís Vilanova
  2017-06-18 14:20     ` Lluís Vilanova
  1 sibling, 2 replies; 34+ messages in thread
From: Emilio G. Cota @ 2017-06-15 23:25 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: Paolo Bonzini, Richard Henderson, Alex Bennée, qemu-devel,
	Peter Crosthwaite

On Thu, Jun 15, 2017 at 18:19:11 -0400, Emilio G. Cota wrote:
> (snip)
> > +/**
> > + * 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;
> 
> - @pc_next: I'd stick with @pc, it's shorter, it's everywhere already, and
>   with the documentation it's very clear what it is for.
> - @jmp_type: missing doc :-)

Also, consider keeping the @is_jmp name instead of renaming it to
@jmp_type. (@jmp would be shorter but it would be confusing though,
e.g. cris has both dc->jmp and dc->is_jmp.)

		E.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 6/6] target: [tcg, arm] Port to generic translation framework
  2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 6/6] target: [tcg, arm] Port to generic translation framework Lluís Vilanova
@ 2017-06-16  0:18   ` Emilio G. Cota
  2017-06-18 14:41     ` Lluís Vilanova
  0 siblings, 1 reply; 34+ messages in thread
From: Emilio G. Cota @ 2017-06-16  0:18 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Peter Maydell, Peter Crosthwaite, open list:ARM,
	Paolo Bonzini, Alex Bennée, Richard Henderson

On Mon, Jun 12, 2017 at 17:54:30 +0300, Lluís Vilanova wrote:
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> ---
>  target/arm/translate-a64.c |  346 ++++++++++-----------
>  target/arm/translate.c     |  720 ++++++++++++++++++++++----------------------
>  target/arm/translate.h     |   46 ++-
>  3 files changed, 560 insertions(+), 552 deletions(-)

This one makes my arm-softmmu hang while booting debian. The last line
I see is:

> Freeing unused kernel memory: 300K (80669000 - 806b4000)

Note that this happens even after disabling goto_ptr, so it shouldn't
be related to that feature.

The problem might be with the rebase. For instance, the
hunk below was modified by commit 542b3478a ("armv7m: Replace armv7m.hack
with unassigned_access handler"). Might be a good idea to go over
the latest changes to arm/translate.c. What commit was your last working
version based on?

(snip)
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index 96272a9888..06f207a5f6 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> +#else
> +    if (dc->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;
> +    }
> +#endif
> +}

Thanks,

		Emilio

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code()
  2017-06-12 14:53 ` [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
                     ` (2 preceding siblings ...)
  2017-06-14 22:30   ` Laurent Vivier
@ 2017-06-16 14:07   ` Alex Bennée
  3 siblings, 0 replies; 34+ messages in thread
From: Alex Bennée @ 2017-06-16 14:07 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Richard Henderson, Peter Crosthwaite, Paolo Bonzini,
	Peter Maydell, Edgar E. Iglesias, Eduardo Habkost, Michael Walle,
	Laurent Vivier, Aurelien Jarno, Yongbok Kim, Anthony Green,
	Stafford Horne, David Gibson, Alexander Graf, Mark Cave-Ayland,
	Artyom Tarasenko, Bastian Koppelmann, Guan Xuetao, Max Filippov,
	open list:ARM, open list:PowerPC


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Needed to implement a target-agnostic gen_intermediate_code() in the
> future.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> Reviewed-by: Richard Henderson <rth@twiddle.net>

ARM bits look good

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/exec/exec-all.h       |    2 +-
>  target/alpha/translate.c      |   11 +++++------
>  target/arm/translate.c        |   20 ++++++++++----------
>  target/cris/translate.c       |   17 ++++++++---------
>  target/i386/translate.c       |   13 ++++++-------
>  target/lm32/translate.c       |   22 +++++++++++-----------
>  target/m68k/translate.c       |   15 +++++++--------
>  target/microblaze/translate.c |   22 +++++++++++-----------
>  target/mips/translate.c       |   15 +++++++--------
>  target/moxie/translate.c      |   14 +++++++-------
>  target/openrisc/translate.c   |   19 ++++++++++---------
>  target/ppc/translate.c        |   15 +++++++--------
>  target/s390x/translate.c      |   13 ++++++-------
>  target/sh4/translate.c        |   15 +++++++--------
>  target/sparc/translate.c      |   11 +++++------
>  target/tilegx/translate.c     |    7 +++----
>  target/tricore/translate.c    |    9 ++++-----
>  target/unicore32/translate.c  |   17 ++++++++---------
>  target/xtensa/translate.c     |   13 ++++++-------
>  translate-all.c               |    2 +-
>  20 files changed, 130 insertions(+), 142 deletions(-)
>
> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> index 87ae10bcc9..1ec7637170 100644
> --- a/include/exec/exec-all.h
> +++ b/include/exec/exec-all.h
> @@ -43,7 +43,7 @@ typedef ram_addr_t tb_page_addr_t;
>
>  #include "qemu/log.h"
>
> -void gen_intermediate_code(CPUArchState *env, struct TranslationBlock *tb);
> +void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
>  void restore_state_to_opc(CPUArchState *env, struct TranslationBlock *tb,
>                            target_ulong *data);
>
> diff --git a/target/alpha/translate.c b/target/alpha/translate.c
> index 7c45ae360c..9b60680454 100644
> --- a/target/alpha/translate.c
> +++ b/target/alpha/translate.c
> @@ -2900,10 +2900,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
>      return ret;
>  }
>
> -void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    AlphaCPU *cpu = alpha_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUAlphaState *env = cpu->env_ptr;
>      DisasContext ctx, *ctxp = &ctx;
>      target_ulong pc_start;
>      target_ulong pc_mask;
> @@ -2918,7 +2917,7 @@ void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
>      ctx.pc = pc_start;
>      ctx.mem_idx = cpu_mmu_index(env, false);
>      ctx.implver = env->implver;
> -    ctx.singlestep_enabled = cs->singlestep_enabled;
> +    ctx.singlestep_enabled = cpu->singlestep_enabled;
>
>  #ifdef CONFIG_USER_ONLY
>      ctx.ir = cpu_std_ir;
> @@ -2961,7 +2960,7 @@ void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(ctx.pc);
>          num_insns++;
>
> -        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, ctx.pc, BP_ANY))) {
>              ret = gen_excp(&ctx, EXCP_DEBUG, 0);
>              /* The address covered by the breakpoint must be included in
>                 [tb->pc, tb->pc + tb->size) in order to for it to be
> @@ -3030,7 +3029,7 @@ void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
>          && qemu_log_in_addr_range(pc_start)) {
>          qemu_log_lock();
>          qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -        log_target_disas(cs, pc_start, ctx.pc - pc_start, 1);
> +        log_target_disas(cpu, pc_start, ctx.pc - pc_start, 1);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index 0862f9e4aa..96272a9888 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -11787,10 +11787,10 @@ static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
>  {
> -    ARMCPU *cpu = arm_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUARMState *env = cpu->env_ptr;
> +    ARMCPU *arm_cpu = arm_env_get_cpu(env);
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_start;
>      target_ulong next_page_start;
> @@ -11804,7 +11804,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
>       * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
>       */
>      if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
> -        gen_intermediate_code_a64(cpu, tb);
> +        gen_intermediate_code_a64(arm_cpu, tb);
>          return;
>      }
>
> @@ -11814,7 +11814,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
>
>      dc->is_jmp = DISAS_NEXT;
>      dc->pc = pc_start;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>      dc->condjmp = 0;
>
>      dc->aarch64 = 0;
> @@ -11840,7 +11840,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
>      dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
>      dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(tb->flags);
>      dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(tb->flags);
> -    dc->cp_regs = cpu->cp_regs;
> +    dc->cp_regs = arm_cpu->cp_regs;
>      dc->features = env->features;
>
>      /* Single step state. The code-generation logic here is:
> @@ -11941,9 +11941,9 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
>          }
>  #endif
>
> -        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
> +        if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
>              CPUBreakpoint *bp;
> -            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
> +            QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
>                  if (bp->pc == dc->pc) {
>                      if (bp->flags & BP_CPU) {
>                          gen_set_condexec(dc);
> @@ -12042,7 +12042,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
>          if (dc->condjmp) {
>              /* FIXME:  This can theoretically happen with self-modifying
>                 code.  */
> -            cpu_abort(cs, "IO on conditional branch instruction");
> +            cpu_abort(cpu, "IO on conditional branch instruction");
>          }
>          gen_io_end();
>      }
> @@ -12156,7 +12156,7 @@ done_generating:
>          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,
> +        log_target_disas(cpu, pc_start, dc->pc - pc_start,
>                           dc->thumb | (dc->sctlr_b << 1));
>          qemu_log("\n");
>          qemu_log_unlock();
> diff --git a/target/cris/translate.c b/target/cris/translate.c
> index 0ee05ca02d..35931e7061 100644
> --- a/target/cris/translate.c
> +++ b/target/cris/translate.c
> @@ -3080,10 +3080,9 @@ static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc)
>   */
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    CRISCPU *cpu = cris_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUCRISState *env = cpu->env_ptr;
>      uint32_t pc_start;
>      unsigned int insn_len;
>      struct DisasContext ctx;
> @@ -3105,13 +3104,13 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
>       * delayslot, like in real hw.
>       */
>      pc_start = tb->pc & ~1;
> -    dc->cpu = cpu;
> +    dc->cpu = cris_env_get_cpu(env);
>      dc->tb = tb;
>
>      dc->is_jmp = DISAS_NEXT;
>      dc->ppc = pc_start;
>      dc->pc = pc_start;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>      dc->flags_uptodate = 1;
>      dc->flagx_known = 1;
>      dc->flags_x = tb->flags & X_FLAG;
> @@ -3151,7 +3150,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
>                             ? dc->ppc | 1 : dc->pc);
>          num_insns++;
>
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              cris_evaluate_flags(dc);
>              tcg_gen_movi_tl(env_pc, dc->pc);
>              t_gen_raise_exception(EXCP_DEBUG);
> @@ -3225,7 +3224,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
>
>          /* If we are rexecuting a branch due to exceptions on
>             delay slots don't break.  */
> -        if (!(tb->pc & 1) && cs->singlestep_enabled) {
> +        if (!(tb->pc & 1) && cpu->singlestep_enabled) {
>              break;
>          }
>      } while (!dc->is_jmp && !dc->cpustate_changed
> @@ -3258,7 +3257,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
>
>      cris_evaluate_flags(dc);
>
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          if (dc->is_jmp == DISAS_NEXT) {
>              tcg_gen_movi_tl(env_pc, npc);
>          }
> @@ -3293,7 +3292,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
>          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,
> +        log_target_disas(cpu, pc_start, dc->pc - pc_start,
>                           env->pregs[PR_VR]);
>          qemu_log("\nisize=%d osize=%d\n",
>                   dc->pc - pc_start, tcg_op_buf_count());
> diff --git a/target/i386/translate.c b/target/i386/translate.c
> index 674ec96d5a..b38bcabfc2 100644
> --- a/target/i386/translate.c
> +++ b/target/i386/translate.c
> @@ -8366,10 +8366,9 @@ void tcg_x86_init(void)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
>  {
> -    X86CPU *cpu = x86_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUX86State *env = cpu->env_ptr;
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_ptr;
>      uint32_t flags;
> @@ -8392,7 +8391,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
>      dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
>      dc->iopl = (flags >> IOPL_SHIFT) & 3;
>      dc->tf = (flags >> TF_SHIFT) & 1;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>      dc->cc_op = CC_OP_DYNAMIC;
>      dc->cc_op_dirty = false;
>      dc->cs_base = cs_base;
> @@ -8414,7 +8413,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
>      dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
>  #endif
>      dc->flags = flags;
> -    dc->jmp_opt = !(dc->tf || cs->singlestep_enabled ||
> +    dc->jmp_opt = !(dc->tf || cpu->singlestep_enabled ||
>                      (flags & HF_INHIBIT_IRQ_MASK));
>      /* Do not optimize repz jumps at all in icount mode, because
>         rep movsS instructions are execured with different paths
> @@ -8463,7 +8462,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
>          num_insns++;
>
>          /* If RF is set, suppress an internally generated breakpoint.  */
> -        if (unlikely(cpu_breakpoint_test(cs, pc_ptr,
> +        if (unlikely(cpu_breakpoint_test(cpu, pc_ptr,
>                                           tb->flags & HF_RF_MASK
>                                           ? BP_GDB : BP_ANY))) {
>              gen_debug(dc, pc_ptr - dc->cs_base);
> @@ -8539,7 +8538,7 @@ done_generating:
>          else
>  #endif
>              disas_flags = !dc->code32;
> -        log_target_disas(cs, pc_start, pc_ptr - pc_start, disas_flags);
> +        log_target_disas(cpu, pc_start, pc_ptr - pc_start, disas_flags);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/lm32/translate.c b/target/lm32/translate.c
> index 692882f447..0ac34fc620 100644
> --- a/target/lm32/translate.c
> +++ b/target/lm32/translate.c
> @@ -1044,10 +1044,10 @@ static inline void decode(DisasContext *dc, uint32_t ir)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    LM32CPU *cpu = lm32_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPULM32State *env = cpu->env_ptr;
> +    LM32CPU *lm32_cpu = lm32_env_get_cpu(env);
>      struct DisasContext ctx, *dc = &ctx;
>      uint32_t pc_start;
>      uint32_t next_page_start;
> @@ -1055,14 +1055,14 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
>      int max_insns;
>
>      pc_start = tb->pc;
> -    dc->features = cpu->features;
> -    dc->num_breakpoints = cpu->num_breakpoints;
> -    dc->num_watchpoints = cpu->num_watchpoints;
> +    dc->features = lm32_cpu->features;
> +    dc->num_breakpoints = lm32_cpu->num_breakpoints;
> +    dc->num_watchpoints = lm32_cpu->num_watchpoints;
>      dc->tb = tb;
>
>      dc->is_jmp = DISAS_NEXT;
>      dc->pc = pc_start;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>
>      if (pc_start & 3) {
>          qemu_log_mask(LOG_GUEST_ERROR,
> @@ -1085,7 +1085,7 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(dc->pc);
>          num_insns++;
>
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              tcg_gen_movi_tl(cpu_pc, dc->pc);
>              t_gen_raise_exception(dc, EXCP_DEBUG);
>              dc->is_jmp = DISAS_UPDATE;
> @@ -1108,7 +1108,7 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
>          dc->pc += 4;
>      } while (!dc->is_jmp
>           && !tcg_op_buf_full()
> -         && !cs->singlestep_enabled
> +         && !cpu->singlestep_enabled
>           && !singlestep
>           && (dc->pc < next_page_start)
>           && num_insns < max_insns);
> @@ -1117,7 +1117,7 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
>          gen_io_end();
>      }
>
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          if (dc->is_jmp == DISAS_NEXT) {
>              tcg_gen_movi_tl(cpu_pc, dc->pc);
>          }
> @@ -1150,7 +1150,7 @@ void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
>          && qemu_log_in_addr_range(pc_start)) {
>          qemu_log_lock();
>          qemu_log("\n");
> -        log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
> +        log_target_disas(cpu, pc_start, dc->pc - pc_start, 0);
>          qemu_log("\nisize=%d osize=%d\n",
>                   dc->pc - pc_start, tcg_op_buf_count());
>          qemu_log_unlock();
> diff --git a/target/m68k/translate.c b/target/m68k/translate.c
> index ad4d4efb8d..0a3372818c 100644
> --- a/target/m68k/translate.c
> +++ b/target/m68k/translate.c
> @@ -5039,10 +5039,9 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
>  {
> -    M68kCPU *cpu = m68k_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUM68KState *env = cpu->env_ptr;
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_start;
>      int pc_offset;
> @@ -5059,7 +5058,7 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
>      dc->pc = pc_start;
>      dc->cc_op = CC_OP_DYNAMIC;
>      dc->cc_op_synced = 1;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>      dc->fpcr = env->fpcr;
>      dc->user = (env->sr & SR_S) == 0;
>      dc->done_mac = 0;
> @@ -5080,7 +5079,7 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
>          tcg_gen_insn_start(dc->pc, dc->cc_op);
>          num_insns++;
>
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              gen_exception(dc, dc->pc, EXCP_DEBUG);
>              dc->is_jmp = DISAS_JUMP;
>              /* The address covered by the breakpoint must be included in
> @@ -5098,14 +5097,14 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
>          dc->insn_pc = dc->pc;
>  	disas_m68k_insn(env, dc);
>      } while (!dc->is_jmp && !tcg_op_buf_full() &&
> -             !cs->singlestep_enabled &&
> +             !cpu->singlestep_enabled &&
>               !singlestep &&
>               (pc_offset) < (TARGET_PAGE_SIZE - 32) &&
>               num_insns < max_insns);
>
>      if (tb->cflags & CF_LAST_IO)
>          gen_io_end();
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          /* Make sure the pc is updated, and raise a debug exception.  */
>          if (!dc->is_jmp) {
>              update_cc_op(dc);
> @@ -5138,7 +5137,7 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
>          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, 0);
> +        log_target_disas(cpu, pc_start, dc->pc - pc_start, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
> index 0bb609513c..d5f499658d 100644
> --- a/target/microblaze/translate.c
> +++ b/target/microblaze/translate.c
> @@ -1594,10 +1594,10 @@ static inline void decode(DisasContext *dc, uint32_t ir)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    MicroBlazeCPU *cpu = mb_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUMBState *env = cpu->env_ptr;
> +    MicroBlazeCPU *mb_cpu = mb_env_get_cpu(env);
>      uint32_t pc_start;
>      struct DisasContext ctx;
>      struct DisasContext *dc = &ctx;
> @@ -1607,7 +1607,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>      int max_insns;
>
>      pc_start = tb->pc;
> -    dc->cpu = cpu;
> +    dc->cpu = mb_cpu;
>      dc->tb = tb;
>      org_flags = dc->synced_flags = dc->tb_flags = tb->flags;
>
> @@ -1618,13 +1618,13 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>          dc->jmp = JMP_INDIRECT;
>      }
>      dc->pc = pc_start;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>      dc->cpustate_changed = 0;
>      dc->abort_at_next_insn = 0;
>      dc->nr_nops = 0;
>
>      if (pc_start & 3) {
> -        cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start);
> +        cpu_abort(cpu, "Microblaze: unaligned PC=%x\n", pc_start);
>      }
>
>      next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
> @@ -1650,7 +1650,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>          }
>  #endif
>
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              t_gen_raise_exception(dc, EXCP_DEBUG);
>              dc->is_jmp = DISAS_UPDATE;
>              /* The address covered by the breakpoint must be included in
> @@ -1707,7 +1707,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>                  break;
>              }
>          }
> -        if (cs->singlestep_enabled) {
> +        if (cpu->singlestep_enabled) {
>              break;
>          }
>      } while (!dc->is_jmp && !dc->cpustate_changed
> @@ -1728,7 +1728,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>
>      if (tb->cflags & CF_LAST_IO)
>          gen_io_end();
> -    /* Force an update if the per-tb cpu state has changed.  */
> +    /* Force an update if the per-tb mb_cpu state has changed.  */
>      if (dc->is_jmp == DISAS_NEXT
>          && (dc->cpustate_changed || org_flags != dc->tb_flags)) {
>          dc->is_jmp = DISAS_UPDATE;
> @@ -1736,7 +1736,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>      }
>      t_sync_flags(dc);
>
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
>
>          if (dc->is_jmp != DISAS_JUMP) {
> @@ -1773,7 +1773,7 @@ void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
>          qemu_log_lock();
>          qemu_log("--------------\n");
>  #if DISAS_GNU
> -        log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
> +        log_target_disas(cpu, pc_start, dc->pc - pc_start, 0);
>  #endif
>          qemu_log("\nisize=%d osize=%d\n",
>                   dc->pc - pc_start, tcg_op_buf_count());
> diff --git a/target/mips/translate.c b/target/mips/translate.c
> index 559f8fed89..1f9e02f426 100644
> --- a/target/mips/translate.c
> +++ b/target/mips/translate.c
> @@ -19878,10 +19878,9 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
>      }
>  }
>
> -void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    MIPSCPU *cpu = mips_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUMIPSState *env = cpu->env_ptr;
>      DisasContext ctx;
>      target_ulong pc_start;
>      target_ulong next_page_start;
> @@ -19894,7 +19893,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
>      next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>      ctx.pc = pc_start;
>      ctx.saved_pc = -1;
> -    ctx.singlestep_enabled = cs->singlestep_enabled;
> +    ctx.singlestep_enabled = cpu->singlestep_enabled;
>      ctx.insn_flags = env->insn_flags;
>      ctx.CP0_Config1 = env->CP0_Config1;
>      ctx.tb = tb;
> @@ -19941,7 +19940,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(ctx.pc, ctx.hflags & MIPS_HFLAG_BMASK, ctx.btarget);
>          num_insns++;
>
> -        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, ctx.pc, BP_ANY))) {
>              save_cpu_state(&ctx, 1);
>              ctx.bstate = BS_BRANCH;
>              gen_helper_raise_exception_debug(cpu_env);
> @@ -19996,7 +19995,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
>             This is what GDB expects and is consistent with what the
>             hardware does (e.g. if a delay slot instruction faults, the
>             reported PC is the PC of the branch).  */
> -        if (cs->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0) {
> +        if (cpu->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0) {
>              break;
>          }
>
> @@ -20017,7 +20016,7 @@ void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
>      if (tb->cflags & CF_LAST_IO) {
>          gen_io_end();
>      }
> -    if (cs->singlestep_enabled && ctx.bstate != BS_BRANCH) {
> +    if (cpu->singlestep_enabled && ctx.bstate != BS_BRANCH) {
>          save_cpu_state(&ctx, ctx.bstate != BS_EXCP);
>          gen_helper_raise_exception_debug(cpu_env);
>      } else {
> @@ -20049,7 +20048,7 @@ done_generating:
>          && qemu_log_in_addr_range(pc_start)) {
>          qemu_log_lock();
>          qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -        log_target_disas(cs, pc_start, ctx.pc - pc_start, 0);
> +        log_target_disas(cpu, pc_start, ctx.pc - pc_start, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/moxie/translate.c b/target/moxie/translate.c
> index 0660b44c08..176063a1de 100644
> --- a/target/moxie/translate.c
> +++ b/target/moxie/translate.c
> @@ -822,10 +822,10 @@ static int decode_opc(MoxieCPU *cpu, DisasContext *ctx)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    MoxieCPU *cpu = moxie_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUMoxieState *env = cpu->env_ptr;
> +    MoxieCPU *moxie_cpu = moxie_env_get_cpu(env);
>      DisasContext ctx;
>      target_ulong pc_start;
>      int num_insns, max_insns;
> @@ -851,7 +851,7 @@ void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(ctx.pc);
>          num_insns++;
>
> -        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, ctx.pc, BP_ANY))) {
>              tcg_gen_movi_i32(cpu_pc, ctx.pc);
>              gen_helper_debug(cpu_env);
>              ctx.bstate = BS_EXCP;
> @@ -864,12 +864,12 @@ void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
>          }
>
>          ctx.opcode = cpu_lduw_code(env, ctx.pc);
> -        ctx.pc += decode_opc(cpu, &ctx);
> +        ctx.pc += decode_opc(moxie_cpu, &ctx);
>
>          if (num_insns >= max_insns) {
>              break;
>          }
> -        if (cs->singlestep_enabled) {
> +        if (cpu->singlestep_enabled) {
>              break;
>          }
>          if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) {
> @@ -877,7 +877,7 @@ void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
>          }
>      } while (ctx.bstate == BS_NONE && !tcg_op_buf_full());
>
> -    if (cs->singlestep_enabled) {
> +    if (cpu->singlestep_enabled) {
>          tcg_gen_movi_tl(cpu_pc, ctx.pc);
>          gen_helper_debug(cpu_env);
>      } else {
> diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
> index e49518e893..aaac359d5b 100644
> --- a/target/openrisc/translate.c
> +++ b/target/openrisc/translate.c
> @@ -1518,9 +1518,10 @@ static void disas_openrisc_insn(DisasContext *dc, OpenRISCCPU *cpu)
>      }
>  }
>
> -void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
> +    OpenRISCState *env = cpu->env_ptr;
> +    OpenRISCCPU *or_cpu = openrisc_env_get_cpu(env);
>      CPUState *cs = CPU(cpu);
>      struct DisasContext ctx, *dc = &ctx;
>      uint32_t pc_start;
> @@ -1533,10 +1534,10 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
>
>      dc->is_jmp = DISAS_NEXT;
>      dc->pc = pc_start;
> -    dc->mem_idx = cpu_mmu_index(&cpu->env, false);
> +    dc->mem_idx = cpu_mmu_index(&or_cpu->env, false);
>      dc->tb_flags = tb->flags;
>      dc->delayed_branch = (dc->tb_flags & TB_FLAGS_DFLAG) != 0;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>
>      next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>      num_insns = 0;
> @@ -1571,7 +1572,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
>  			   | (num_insns ? 2 : 0));
>          num_insns++;
>
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              tcg_gen_movi_tl(cpu_pc, dc->pc);
>              gen_exception(dc, EXCP_DEBUG);
>              dc->is_jmp = DISAS_UPDATE;
> @@ -1586,7 +1587,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
>          if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
>              gen_io_start();
>          }
> -        disas_openrisc_insn(dc, cpu);
> +        disas_openrisc_insn(dc, or_cpu);
>          dc->pc = dc->pc + 4;
>
>          /* delay slot */
> @@ -1601,7 +1602,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
>          }
>      } while (!dc->is_jmp
>               && !tcg_op_buf_full()
> -             && !cs->singlestep_enabled
> +             && !cpu->singlestep_enabled
>               && !singlestep
>               && (dc->pc < next_page_start)
>               && num_insns < max_insns);
> @@ -1619,7 +1620,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
>          dc->is_jmp = DISAS_UPDATE;
>          tcg_gen_movi_tl(cpu_pc, dc->pc);
>      }
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          gen_exception(dc, EXCP_DEBUG);
>      } else {
>          switch (dc->is_jmp) {
> @@ -1647,7 +1648,7 @@ void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
>
>      if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
>          && qemu_log_in_addr_range(pc_start)) {
> -        log_target_disas(cs, pc_start, tb->size, 0);
> +        log_target_disas(cpu, pc_start, tb->size, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index c0cd64d927..9a934117d8 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -7203,10 +7203,9 @@ void ppc_cpu_dump_statistics(CPUState *cs, FILE*f,
>  }
>
>  /*****************************************************************************/
> -void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    PowerPCCPU *cpu = ppc_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = cpu->env_ptr;
>      DisasContext ctx, *ctxp = &ctx;
>      opc_handler_t **table, *handler;
>      target_ulong pc_start;
> @@ -7267,7 +7266,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
>          ctx.singlestep_enabled = 0;
>      if ((env->flags & POWERPC_FLAG_BE) && msr_be)
>          ctx.singlestep_enabled |= CPU_BRANCH_STEP;
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP;
>      }
>  #if defined (DO_SINGLE_STEP) && 0
> @@ -7290,7 +7289,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(ctx.nip);
>          num_insns++;
>
> -        if (unlikely(cpu_breakpoint_test(cs, ctx.nip, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, ctx.nip, BP_ANY))) {
>              gen_debug_exception(ctxp);
>              /* The address covered by the breakpoint must be included in
>                 [tb->pc, tb->pc + tb->size) in order to for it to be
> @@ -7369,7 +7368,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
>                       ctx.exception != POWERPC_EXCP_BRANCH)) {
>              gen_exception_nip(ctxp, POWERPC_EXCP_TRACE, ctx.nip);
>          } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
> -                            (cs->singlestep_enabled) ||
> +                            (cpu->singlestep_enabled) ||
>                              singlestep ||
>                              num_insns >= max_insns)) {
>              /* if we reach a page boundary or are single stepping, stop
> @@ -7389,7 +7388,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
>      if (ctx.exception == POWERPC_EXCP_NONE) {
>          gen_goto_tb(&ctx, 0, ctx.nip);
>      } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
> -        if (unlikely(cs->singlestep_enabled)) {
> +        if (unlikely(cpu->singlestep_enabled)) {
>              gen_debug_exception(ctxp);
>          }
>          /* Generate the return instruction */
> @@ -7408,7 +7407,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
>          flags |= ctx.le_mode << 16;
>          qemu_log_lock();
>          qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -        log_target_disas(cs, pc_start, ctx.nip - pc_start, flags);
> +        log_target_disas(cpu, pc_start, ctx.nip - pc_start, flags);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/s390x/translate.c b/target/s390x/translate.c
> index 95f91d4f08..2a17b3d7aa 100644
> --- a/target/s390x/translate.c
> +++ b/target/s390x/translate.c
> @@ -5714,10 +5714,9 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s)
>      return ret;
>  }
>
> -void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    S390CPU *cpu = s390_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUS390XState *env = cpu->env_ptr;
>      DisasContext dc;
>      target_ulong pc_start;
>      uint64_t next_page_start;
> @@ -5736,7 +5735,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
>      dc.pc = pc_start;
>      dc.cc_op = CC_OP_DYNAMIC;
>      dc.ex_value = tb->cs_base;
> -    do_debug = dc.singlestep_enabled = cs->singlestep_enabled;
> +    do_debug = dc.singlestep_enabled = cpu->singlestep_enabled;
>
>      next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>
> @@ -5755,7 +5754,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(dc.pc, dc.cc_op);
>          num_insns++;
>
> -        if (unlikely(cpu_breakpoint_test(cs, dc.pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc.pc, BP_ANY))) {
>              status = EXIT_PC_STALE;
>              do_debug = true;
>              /* The address covered by the breakpoint must be included in
> @@ -5779,7 +5778,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
>                  || tcg_op_buf_full()
>                  || num_insns >= max_insns
>                  || singlestep
> -                || cs->singlestep_enabled
> +                || cpu->singlestep_enabled
>                  || dc.ex_value)) {
>              status = EXIT_PC_STALE;
>          }
> @@ -5829,7 +5828,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
>              qemu_log("IN: EXECUTE %016" PRIx64 "\n", dc.ex_value);
>          } else {
>              qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -            log_target_disas(cs, pc_start, dc.pc - pc_start, 1);
> +            log_target_disas(cpu, pc_start, dc.pc - pc_start, 1);
>              qemu_log("\n");
>          }
>          qemu_log_unlock();
> diff --git a/target/sh4/translate.c b/target/sh4/translate.c
> index 8bc132b27b..6a797072d4 100644
> --- a/target/sh4/translate.c
> +++ b/target/sh4/translate.c
> @@ -1815,10 +1815,9 @@ static void decode_opc(DisasContext * ctx)
>      }
>  }
>
> -void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    SuperHCPU *cpu = sh_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUSH4State *env = cpu->env_ptr;
>      DisasContext ctx;
>      target_ulong pc_start;
>      int num_insns;
> @@ -1834,7 +1833,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
>         so assume it is a dynamic branch.  */
>      ctx.delayed_pc = -1; /* use delayed pc from env pointer */
>      ctx.tb = tb;
> -    ctx.singlestep_enabled = cs->singlestep_enabled;
> +    ctx.singlestep_enabled = cpu->singlestep_enabled;
>      ctx.features = env->features;
>      ctx.has_movcal = (ctx.tbflags & TB_FLAG_PENDING_MOVCA);
>
> @@ -1852,7 +1851,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
>          tcg_gen_insn_start(ctx.pc, ctx.envflags);
>          num_insns++;
>
> -        if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, ctx.pc, BP_ANY))) {
>              /* We have hit a breakpoint - make sure PC is up-to-date */
>              gen_save_cpu_state(&ctx, true);
>              gen_helper_debug(cpu_env);
> @@ -1874,7 +1873,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
>  	ctx.pc += 2;
>  	if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
>  	    break;
> -        if (cs->singlestep_enabled) {
> +        if (cpu->singlestep_enabled) {
>  	    break;
>          }
>          if (num_insns >= max_insns)
> @@ -1884,7 +1883,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
>      }
>      if (tb->cflags & CF_LAST_IO)
>          gen_io_end();
> -    if (cs->singlestep_enabled) {
> +    if (cpu->singlestep_enabled) {
>          gen_save_cpu_state(&ctx, true);
>          gen_helper_debug(cpu_env);
>      } else {
> @@ -1915,7 +1914,7 @@ void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
>          && qemu_log_in_addr_range(pc_start)) {
>          qemu_log_lock();
>  	qemu_log("IN:\n");	/* , lookup_symbol(pc_start)); */
> -        log_target_disas(cs, pc_start, ctx.pc - pc_start, 0);
> +        log_target_disas(cpu, pc_start, ctx.pc - pc_start, 0);
>  	qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/sparc/translate.c b/target/sparc/translate.c
> index aa6734d54e..90c43e4460 100644
> --- a/target/sparc/translate.c
> +++ b/target/sparc/translate.c
> @@ -5747,10 +5747,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
>      }
>  }
>
> -void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
> +void gen_intermediate_code(CPUState *cpu, TranslationBlock * tb)
>  {
> -    SPARCCPU *cpu = sparc_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUSPARCState *env = cpu->env_ptr;
>      target_ulong pc_start, last_pc;
>      DisasContext dc1, *dc = &dc1;
>      int num_insns;
> @@ -5768,7 +5767,7 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
>      dc->def = env->def;
>      dc->fpu_enabled = tb_fpu_enabled(tb->flags);
>      dc->address_mask_32bit = tb_am_enabled(tb->flags);
> -    dc->singlestep = (cs->singlestep_enabled || singlestep);
> +    dc->singlestep = (cpu->singlestep_enabled || singlestep);
>  #ifndef CONFIG_USER_ONLY
>      dc->supervisor = (tb->flags & TB_FLAG_SUPER) != 0;
>  #endif
> @@ -5800,7 +5799,7 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
>          num_insns++;
>          last_pc = dc->pc;
>
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              if (dc->pc != pc_start) {
>                  save_state(dc);
>              }
> @@ -5864,7 +5863,7 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
>          qemu_log_lock();
>          qemu_log("--------------\n");
>          qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -        log_target_disas(cs, pc_start, last_pc + 4 - pc_start, 0);
> +        log_target_disas(cpu, pc_start, last_pc + 4 - pc_start, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/tilegx/translate.c b/target/tilegx/translate.c
> index ff2ef7b63d..a86e9e9d22 100644
> --- a/target/tilegx/translate.c
> +++ b/target/tilegx/translate.c
> @@ -2370,12 +2370,11 @@ static void translate_one_bundle(DisasContext *dc, uint64_t bundle)
>      }
>  }
>
> -void gen_intermediate_code(CPUTLGState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    TileGXCPU *cpu = tilegx_env_get_cpu(env);
> +    CPUTLGState *env = cpu->env_ptr;
>      DisasContext ctx;
>      DisasContext *dc = &ctx;
> -    CPUState *cs = CPU(cpu);
>      uint64_t pc_start = tb->pc;
>      uint64_t next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>      int num_insns = 0;
> @@ -2397,7 +2396,7 @@ void gen_intermediate_code(CPUTLGState *env, struct TranslationBlock *tb)
>      if (!max_insns) {
>          max_insns = CF_COUNT_MASK;
>      }
> -    if (cs->singlestep_enabled || singlestep) {
> +    if (cpu->singlestep_enabled || singlestep) {
>          max_insns = 1;
>      }
>      if (max_insns > TCG_MAX_INSNS) {
> diff --git a/target/tricore/translate.c b/target/tricore/translate.c
> index ddd2dd07dd..1930da2f2a 100644
> --- a/target/tricore/translate.c
> +++ b/target/tricore/translate.c
> @@ -8782,10 +8782,9 @@ static void decode_opc(CPUTriCoreState *env, DisasContext *ctx, int *is_branch)
>      }
>  }
>
> -void gen_intermediate_code(CPUTriCoreState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
>  {
> -    TriCoreCPU *cpu = tricore_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUTriCoreState *env = cpu->env_ptr;
>      DisasContext ctx;
>      target_ulong pc_start;
>      int num_insns, max_insns;
> @@ -8806,7 +8805,7 @@ void gen_intermediate_code(CPUTriCoreState *env, struct TranslationBlock *tb)
>      ctx.pc = pc_start;
>      ctx.saved_pc = -1;
>      ctx.tb = tb;
> -    ctx.singlestep_enabled = cs->singlestep_enabled;
> +    ctx.singlestep_enabled = cpu->singlestep_enabled;
>      ctx.bstate = BS_NONE;
>      ctx.mem_idx = cpu_mmu_index(env, false);
>
> @@ -8840,7 +8839,7 @@ void gen_intermediate_code(CPUTriCoreState *env, struct TranslationBlock *tb)
>          && qemu_log_in_addr_range(pc_start)) {
>          qemu_log_lock();
>          qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -        log_target_disas(cs, pc_start, ctx.pc - pc_start, 0);
> +        log_target_disas(cpu, pc_start, ctx.pc - pc_start, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c
> index 666a2016a8..494ed58c10 100644
> --- a/target/unicore32/translate.c
> +++ b/target/unicore32/translate.c
> @@ -1869,10 +1869,9 @@ static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
>  {
> -    UniCore32CPU *cpu = uc32_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUUniCore32State *env = cpu->env_ptr;
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_start;
>      uint32_t next_page_start;
> @@ -1888,7 +1887,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
>
>      dc->is_jmp = DISAS_NEXT;
>      dc->pc = pc_start;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->singlestep_enabled = cpu->singlestep_enabled;
>      dc->condjmp = 0;
>      cpu_F0s = tcg_temp_new_i32();
>      cpu_F1s = tcg_temp_new_i32();
> @@ -1917,7 +1916,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
>          tcg_gen_insn_start(dc->pc);
>          num_insns++;
>
> -        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc->pc, BP_ANY))) {
>              gen_set_pc_im(dc->pc);
>              gen_exception(EXCP_DEBUG);
>              dc->is_jmp = DISAS_JUMP;
> @@ -1949,7 +1948,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
>           * Also stop translation when a page boundary is reached.  This
>           * ensures prefetch aborts occur at the right place.  */
>      } while (!dc->is_jmp && !tcg_op_buf_full() &&
> -             !cs->singlestep_enabled &&
> +             !cpu->singlestep_enabled &&
>               !singlestep &&
>               dc->pc < next_page_start &&
>               num_insns < max_insns);
> @@ -1958,7 +1957,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
>          if (dc->condjmp) {
>              /* FIXME:  This can theoretically happen with self-modifying
>                 code.  */
> -            cpu_abort(cs, "IO on conditional branch instruction");
> +            cpu_abort(cpu, "IO on conditional branch instruction");
>          }
>          gen_io_end();
>      }
> @@ -1966,7 +1965,7 @@ void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
>      /* At this stage dc->condjmp will only be set when the skipped
>         instruction was a conditional branch or trap, and the PC has
>         already been written.  */
> -    if (unlikely(cs->singlestep_enabled)) {
> +    if (unlikely(cpu->singlestep_enabled)) {
>          /* Make sure the pc is updated, and raise a debug exception.  */
>          if (dc->condjmp) {
>              if (dc->is_jmp == DISAS_SYSCALL) {
> @@ -2027,7 +2026,7 @@ done_generating:
>          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, 0);
> +        log_target_disas(cpu, pc_start, dc->pc - pc_start, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
> index 263002486c..63e4f25c08 100644
> --- a/target/xtensa/translate.c
> +++ b/target/xtensa/translate.c
> @@ -3117,10 +3117,9 @@ static void gen_ibreak_check(CPUXtensaState *env, DisasContext *dc)
>      }
>  }
>
> -void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
>  {
> -    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUXtensaState *env = cpu->env_ptr;
>      DisasContext dc;
>      int insn_count = 0;
>      int max_insns = tb->cflags & CF_COUNT_MASK;
> @@ -3136,7 +3135,7 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
>      }
>
>      dc.config = env->config;
> -    dc.singlestep_enabled = cs->singlestep_enabled;
> +    dc.singlestep_enabled = cpu->singlestep_enabled;
>      dc.tb = tb;
>      dc.pc = pc_start;
>      dc.ring = tb->flags & XTENSA_TBFLAG_RING_MASK;
> @@ -3179,7 +3178,7 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
>          tcg_gen_insn_start(dc.pc);
>          ++insn_count;
>
> -        if (unlikely(cpu_breakpoint_test(cs, dc.pc, BP_ANY))) {
> +        if (unlikely(cpu_breakpoint_test(cpu, dc.pc, BP_ANY))) {
>              tcg_gen_movi_i32(cpu_pc, dc.pc);
>              gen_exception(&dc, EXCP_DEBUG);
>              dc.is_jmp = DISAS_UPDATE;
> @@ -3215,7 +3214,7 @@ void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
>          if (dc.icount) {
>              tcg_gen_mov_i32(cpu_SR[ICOUNT], dc.next_icount);
>          }
> -        if (cs->singlestep_enabled) {
> +        if (cpu->singlestep_enabled) {
>              tcg_gen_movi_i32(cpu_pc, dc.pc);
>              gen_exception(&dc, EXCP_DEBUG);
>              break;
> @@ -3247,7 +3246,7 @@ done:
>          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, 0);
> +        log_target_disas(cpu, pc_start, dc.pc - pc_start, 0);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
> diff --git a/translate-all.c b/translate-all.c
> index b3ee876526..e5de5cace9 100644
> --- a/translate-all.c
> +++ b/translate-all.c
> @@ -1292,7 +1292,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
>      tcg_func_start(&tcg_ctx);
>
>      tcg_ctx.cpu = ENV_GET_CPU(env);
> -    gen_intermediate_code(env, tb);
> +    gen_intermediate_code(cpu, tb);
>      tcg_ctx.cpu = NULL;
>
>      trace_translate_block(tb, tb->pc, tb->tc_ptr);


--
Alex Bennée

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework
  2017-06-15 23:25     ` Emilio G. Cota
@ 2017-06-17  1:09       ` Emilio G. Cota
  2017-06-18 14:24         ` Lluís Vilanova
  2017-06-18 14:22       ` Lluís Vilanova
  1 sibling, 1 reply; 34+ messages in thread
From: Emilio G. Cota @ 2017-06-17  1:09 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: Paolo Bonzini, Peter Crosthwaite, Alex Bennée, qemu-devel,
	Richard Henderson

On Thu, Jun 15, 2017 at 19:25:07 -0400, Emilio G. Cota wrote:
> Also, consider keeping the @is_jmp name instead of renaming it to
> @jmp_type. (@jmp would be shorter but it would be confusing though,
> e.g. cris has both dc->jmp and dc->is_jmp.)

It turns out that keeping the original names also makes the diff's
a lot more bearable.

I have a WIP branch with further modifications to your patches; the goal
is to break down the patchset to make it more easily reviewable, which
hopefully will also prevent us from introducing bugs.

You can see the WIP tree at:
  https://github.com/cota/qemu/tree/trloop
Note that I may rebase this branch any time.

Cheers,

		Emilio

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework
  2017-06-15 22:19   ` [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework Emilio G. Cota
  2017-06-15 23:25     ` Emilio G. Cota
@ 2017-06-18 14:20     ` Lluís Vilanova
  1 sibling, 0 replies; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-18 14:20 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: Paolo Bonzini, Richard Henderson, Alex Bennée, qemu-devel,
	Peter Crosthwaite

Emilio G Cota writes:

> Some minor nits below.
> On Mon, Jun 12, 2017 at 17:54:09 +0300, Lluís Vilanova wrote:
>> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
>> ---
>> +/**
>> + * 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;

> BH_MISS reads out loud to "Breakpoint Hit Miss"; that's quite counterintuitive.
> Similarly for the others (e.g. "breakpoint Hit Hit -- ??".

> Can we just do BP_{MISS,HIT,etc}? Thinking about it, perhaps BP_NONE is
> better than BP_MISS.
[...]

Will do.


Cheers,
  Lluis

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework
  2017-06-15 23:25     ` Emilio G. Cota
  2017-06-17  1:09       ` Emilio G. Cota
@ 2017-06-18 14:22       ` Lluís Vilanova
  2017-06-18 15:47         ` Lluís Vilanova
  1 sibling, 1 reply; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-18 14:22 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: Paolo Bonzini, Peter Crosthwaite, Alex Bennée, qemu-devel,
	Richard Henderson

Emilio G Cota writes:

> On Thu, Jun 15, 2017 at 18:19:11 -0400, Emilio G. Cota wrote:
>> (snip)
>> > +/**
>> > + * 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;
>> 
>> - @pc_next: I'd stick with @pc, it's shorter, it's everywhere already, and
>> with the documentation it's very clear what it is for.
>> - @jmp_type: missing doc :-)

> Also, consider keeping the @is_jmp name instead of renaming it to
> @jmp_type. (@jmp would be shorter but it would be confusing though,
> e.g. cris has both dc->jmp and dc->is_jmp.)

I just figured that this series could also take the chance of trying to rename a
few common variables I'm changing to something more readable.

But if you feel very strongly about keeping the original names (and minimizing
the diffs as you say later), I'll revert the name changes.


Thanks,
  Lluis

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework
  2017-06-17  1:09       ` Emilio G. Cota
@ 2017-06-18 14:24         ` Lluís Vilanova
  0 siblings, 0 replies; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-18 14:24 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: Paolo Bonzini, Richard Henderson, Alex Bennée, qemu-devel,
	Peter Crosthwaite

Emilio G Cota writes:

> On Thu, Jun 15, 2017 at 19:25:07 -0400, Emilio G. Cota wrote:
>> Also, consider keeping the @is_jmp name instead of renaming it to
>> @jmp_type. (@jmp would be shorter but it would be confusing though,
>> e.g. cris has both dc->jmp and dc->is_jmp.)

> It turns out that keeping the original names also makes the diff's
> a lot more bearable.

> I have a WIP branch with further modifications to your patches; the goal
> is to break down the patchset to make it more easily reviewable, which
> hopefully will also prevent us from introducing bugs.

> You can see the WIP tree at:
>   https://github.com/cota/qemu/tree/trloop
> Note that I may rebase this branch any time.

Ok, I'll do that for both arm and x86.


Thanks a lot,
  Lluis

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH] translator mega-patch
  2017-06-15 22:05   ` [Qemu-devel] [PATCH] translator mega-patch Emilio G. Cota
@ 2017-06-18 14:37     ` Lluís Vilanova
  2017-06-18 18:26       ` Peter Maydell
  2017-06-19  4:08       ` Emilio G. Cota
  0 siblings, 2 replies; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-18 14:37 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: qemu-devel, Paolo Bonzini, Peter Crosthwaite, Alex Bennée,
	Richard Henderson

Emilio G Cota writes:

> On Mon, Jun 12, 2017 at 17:54:09 +0300, Lluís Vilanova wrote:
>> Signed-off-by: Lluís Vilanova <vilanova@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 <cota@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

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 6/6] target: [tcg, arm] Port to generic translation framework
  2017-06-16  0:18   ` Emilio G. Cota
@ 2017-06-18 14:41     ` Lluís Vilanova
  2017-06-19  4:22       ` Emilio G. Cota
  0 siblings, 1 reply; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-18 14:41 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: qemu-devel, Peter Maydell, Peter Crosthwaite, open list:ARM,
	Paolo Bonzini, Alex Bennée, Richard Henderson

Emilio G Cota writes:

> On Mon, Jun 12, 2017 at 17:54:30 +0300, Lluís Vilanova wrote:
>> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
>> ---
>> target/arm/translate-a64.c |  346 ++++++++++-----------
>> target/arm/translate.c     |  720 ++++++++++++++++++++++----------------------
>> target/arm/translate.h     |   46 ++-
>> 3 files changed, 560 insertions(+), 552 deletions(-)

> This one makes my arm-softmmu hang while booting debian. The last line
> I see is:

>> Freeing unused kernel memory: 300K (80669000 - 806b4000)

> Note that this happens even after disabling goto_ptr, so it shouldn't
> be related to that feature.

> The problem might be with the rebase. For instance, the
> hunk below was modified by commit 542b3478a ("armv7m: Replace armv7m.hack
> with unassigned_access handler"). Might be a good idea to go over
> the latest changes to arm/translate.c. What commit was your last working
> version based on?

I didn't write it down on the series docs, so I don't really know. I'll break
the patch down into multiple as you suggested, and review them manually to see
if I'm able to catch the error (all the exit reason code is quite burdensome to
port to the new infrastructure).

Is there any ready-made kernel or disk image I can test with?


Thanks,
  Lluis

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic translation framework
  2017-06-15 18:02 ` [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic " Emilio G. Cota
@ 2017-06-18 14:41   ` Lluís Vilanova
  0 siblings, 0 replies; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-18 14:41 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: qemu-devel, Paolo Bonzini, Peter Crosthwaite, Alex Bennée,
	Richard Henderson

Emilio G Cota writes:

> On Mon, Jun 12, 2017 at 17:53:47 +0300, Lluís Vilanova wrote:
>> This series proposes a generic (target-agnostic) instruction translation
>> framework.
>> 
>> It basically provides a generic main loop for instruction disassembly, which
>> calls target-specific functions when necessary. This generalization makes
>> inserting new code in the main loop easier, and helps in keeping all targets in
>> synch as to the contents of it.
>> 
>> This series also paves the way towards adding events to trace guest code
>> execution (BBLs and instructions).
>> 
>> I've ported i386/x86-64 and arm/aarch64 as an example to see how it fits in the
>> current organization, but will port the rest when this series gets merged.

> It seems patch 5 didn't make it through the list (the list drops patches
> sometimes):
>   https://lists.gnu.org/archive/html/qemu-devel/2017-06/msg02833.html

> I think I've found it in your qemu-dbi tree though (1c97cf92b06).
> I pasted it here: https://pastebin.ca/3832616

> 		E.

Yes, I realized that but was waiting to accumulate some changes before sending a
new series. Thanks! :)

Lluis

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework
  2017-06-18 14:22       ` Lluís Vilanova
@ 2017-06-18 15:47         ` Lluís Vilanova
  2017-06-18 21:54           ` Lluís Vilanova
  0 siblings, 1 reply; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-18 15:47 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: Paolo Bonzini, Peter Crosthwaite, Alex Bennée, qemu-devel,
	Richard Henderson

Lluís Vilanova writes:

> Emilio G Cota writes:
>> On Thu, Jun 15, 2017 at 18:19:11 -0400, Emilio G. Cota wrote:
>>> (snip)
>>> > +/**
>>> > + * 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;
>>> 
>>> - @pc_next: I'd stick with @pc, it's shorter, it's everywhere already, and
>>> with the documentation it's very clear what it is for.
>>> - @jmp_type: missing doc :-)

>> Also, consider keeping the @is_jmp name instead of renaming it to
>> @jmp_type. (@jmp would be shorter but it would be confusing though,
>> e.g. cris has both dc->jmp and dc->is_jmp.)

> I just figured that this series could also take the chance of trying to rename a
> few common variables I'm changing to something more readable.

> But if you feel very strongly about keeping the original names (and minimizing
> the diffs as you say later), I'll revert the name changes.

Also, going through the changes to break them down into smaller pieces, I saw
that TranslationBlock (at least in i386) already has a "pc" member, so using
"pc_next" in DisasContextBase makes it even clearer it's a different variable.

You comments still apply to "is_jmp" vs "jmp_type" though. Unless you or anybody
else feels strongly against it, I'll keep "jmp_type", since I'm already changing
all lines that reference "is_jmp" to use DisasContextBase (instead of
DisasContext).


Thanks,
  Lluis

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH] translator mega-patch
  2017-06-18 14:37     ` Lluís Vilanova
@ 2017-06-18 18:26       ` Peter Maydell
  2017-06-19  4:08       ` Emilio G. Cota
  1 sibling, 0 replies; 34+ messages in thread
From: Peter Maydell @ 2017-06-18 18:26 UTC (permalink / raw)
  To: Emilio G. Cota, QEMU Developers, Paolo Bonzini,
	Peter Crosthwaite, Alex Bennée, Richard Henderson

On 18 June 2017 at 15:37, Lluís Vilanova <vilanova@ac.upc.edu> wrote:
> 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?

Multiple targets in one binary is one of those things that I would
like to see us do some day. So while I wouldn't do huge amounts
of work purely to support it, if we have two designs which are
otherwise more-or-less equivalent and only one has a path available
to support multi-target binaries we should probably prefer that one.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework
  2017-06-18 15:47         ` Lluís Vilanova
@ 2017-06-18 21:54           ` Lluís Vilanova
  2017-06-19  4:10             ` Emilio G. Cota
  0 siblings, 1 reply; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-18 21:54 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: Paolo Bonzini, Peter Crosthwaite, Alex Bennée, qemu-devel,
	Richard Henderson

Lluís Vilanova writes:

> Lluís Vilanova writes:
>> Emilio G Cota writes:
>>> On Thu, Jun 15, 2017 at 18:19:11 -0400, Emilio G. Cota wrote:
>>>> (snip)
>>>> > +/**
>>>> > + * 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;
>>>> 
>>>> - @pc_next: I'd stick with @pc, it's shorter, it's everywhere already, and
>>>> with the documentation it's very clear what it is for.
>>>> - @jmp_type: missing doc :-)

>>> Also, consider keeping the @is_jmp name instead of renaming it to
>>> @jmp_type. (@jmp would be shorter but it would be confusing though,
>>> e.g. cris has both dc->jmp and dc->is_jmp.)

>> I just figured that this series could also take the chance of trying to rename a
>> few common variables I'm changing to something more readable.

>> But if you feel very strongly about keeping the original names (and minimizing
>> the diffs as you say later), I'll revert the name changes.

> Also, going through the changes to break them down into smaller pieces, I saw
> that TranslationBlock (at least in i386) already has a "pc" member, so using
> "pc_next" in DisasContextBase makes it even clearer it's a different variable.

> You comments still apply to "is_jmp" vs "jmp_type" though. Unless you or anybody
> else feels strongly against it, I'll keep "jmp_type", since I'm already changing
> all lines that reference "is_jmp" to use DisasContextBase (instead of
> DisasContext).

Aha, just checked your proposed patches more closely and it totally makes sense
to keep "is_jmp" to simplify the diffs, so I'll go for that one.

Thanks!
Lluis

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH] translator mega-patch
  2017-06-18 14:37     ` Lluís Vilanova
  2017-06-18 18:26       ` Peter Maydell
@ 2017-06-19  4:08       ` Emilio G. Cota
  2017-06-19  7:15         ` Peter Maydell
  1 sibling, 1 reply; 34+ messages in thread
From: Emilio G. Cota @ 2017-06-19  4:08 UTC (permalink / raw)
  To: qemu-devel, Paolo Bonzini, Peter Crosthwaite, Alex Bennée,
	Richard Henderson

On Sun, Jun 18, 2017 at 17:37:39 +0300, Lluís Vilanova wrote:
> Emilio G Cota writes:
> 
> > On Mon, Jun 12, 2017 at 17:54:09 +0300, Lluís Vilanova wrote:
> >> Signed-off-by: Lluís Vilanova <vilanova@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?

Yes, I mean the latter.

> I kind of dislike it every time I see container_of, and it makes type
> checking from the compiler a bit more fragile.

container_of is *very* useful! You should like it more :-)

The pattern of having a struct of function pointers ("ops") +
container_of is used in the kernel extensively, and it works
very well there.

The compiler will catch misuses of container_of, which in my
experience is basically all you need. If you want stricter
typing, there's TCON ("typed container"), which is really cool:
  http://ccodearchive.net/info/tcon.html
A neat usage example are type-safe linked lists:
  http://ccodearchive.net/info/tlist2.html

> > 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.

I didn't have this in mind, but it is a nice side effect.

> 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.

Yes performance wouldn't be an issue, even if all we benchmarked was
translation--the key is that the function called is always the same
so prediction takes care of it. See Agner's comment on this (in the
context of C++ though, but it applies here):
> The time it takes to call a virtual member function is a few clock
> cycles more than it takes to call a non-virtual member function, provided
> that the function call statement always calls the same version of the
> virtual function. If the version changes then you may get a misprediction
> penalty of 10 - 20 clock cycles. 
http://www.agner.org/optimize/optimizing_cpp.pdf

Cheers,

		Emilio

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework
  2017-06-18 21:54           ` Lluís Vilanova
@ 2017-06-19  4:10             ` Emilio G. Cota
  2017-06-19  8:37               ` Lluís Vilanova
  0 siblings, 1 reply; 34+ messages in thread
From: Emilio G. Cota @ 2017-06-19  4:10 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: Paolo Bonzini, Peter Crosthwaite, Alex Bennée, qemu-devel,
	Richard Henderson

On Mon, Jun 19, 2017 at 00:54:05 +0300, Lluís Vilanova wrote:
> Aha, just checked your proposed patches more closely and it totally makes sense
> to keep "is_jmp" to simplify the diffs, so I'll go for that one.

Also I think it's important to break down the changes to each
architecture into separate patches, otherwise the diff becomes
impossible to read. I went quite a long way with arm/translate.c
on Friday.

		E.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 6/6] target: [tcg, arm] Port to generic translation framework
  2017-06-18 14:41     ` Lluís Vilanova
@ 2017-06-19  4:22       ` Emilio G. Cota
  0 siblings, 0 replies; 34+ messages in thread
From: Emilio G. Cota @ 2017-06-19  4:22 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Peter Maydell, Peter Crosthwaite, open list:ARM,
	Paolo Bonzini, Alex Bennée, Richard Henderson

On Sun, Jun 18, 2017 at 17:41:02 +0300, Lluís Vilanova wrote:
> Is there any ready-made kernel or disk image I can test with?

I test ARM with:

$ qemu-system-arm -machine type=virt -nographic -smp 1 -m 4096 \
	-netdev user,id=unet,hostfwd=tcp::2222-:22 \
	-device virtio-net-device,netdev=unet \
	-drive file=jessie-arm32-die-on-boot.qcow2,id=myblock,index=0,if=none \
	-device virtio-blk-device,drive=myblock \
	-kernel aarch32-current-linux-kernel-only.img \
	-append 'console=ttyAMA0 root=/dev/vda1' \
	-name arm,debug-threads=on -smp 1

Grab the image & kernel from:
  http://www.cs.columbia.edu/~cota/qemu/
NB. The image shuts down without even asking for a username; it's convenient
for testing/benchmarking.

		E.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH] translator mega-patch
  2017-06-19  4:08       ` Emilio G. Cota
@ 2017-06-19  7:15         ` Peter Maydell
  0 siblings, 0 replies; 34+ messages in thread
From: Peter Maydell @ 2017-06-19  7:15 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: QEMU Developers, Paolo Bonzini, Peter Crosthwaite,
	Alex Bennée, Richard Henderson

On 19 June 2017 at 05:08, Emilio G. Cota <cota@braap.org> wrote:
> On Sun, Jun 18, 2017 at 17:37:39 +0300, Lluís Vilanova wrote:
>> I kind of dislike it every time I see container_of, and it makes type
>> checking from the compiler a bit more fragile.
>
> container_of is *very* useful! You should like it more :-)

Or you could use qom objects, where the parent-to-child
cast is checked.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework
  2017-06-19  4:10             ` Emilio G. Cota
@ 2017-06-19  8:37               ` Lluís Vilanova
  0 siblings, 0 replies; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-19  8:37 UTC (permalink / raw)
  To: Emilio G. Cota
  Cc: Paolo Bonzini, Richard Henderson, Alex Bennée, qemu-devel,
	Peter Crosthwaite

Emilio G Cota writes:

> On Mon, Jun 19, 2017 at 00:54:05 +0300, Lluís Vilanova wrote:
>> Aha, just checked your proposed patches more closely and it totally makes sense
>> to keep "is_jmp" to simplify the diffs, so I'll go for that one.

> Also I think it's important to break down the changes to each
> architecture into separate patches, otherwise the diff becomes
> impossible to read. I went quite a long way with arm/translate.c
> on Friday.

Yes, I'm onto it, thanks :)

Lluis

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 2/6] queue: Add macro for incremental traversal
  2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 2/6] queue: Add macro for incremental traversal Lluís Vilanova
@ 2017-06-19 23:20   ` Richard Henderson
  2017-06-26 12:33     ` Lluís Vilanova
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Henderson @ 2017-06-19 23:20 UTC (permalink / raw)
  To: Lluís Vilanova, qemu-devel
  Cc: Paolo Bonzini, Peter Crosthwaite, Alex Bennée

On 06/12/2017 07:54 AM, Lluís Vilanova wrote:
> Adds macro QTAILQ_FOREACH_CONTINUE to support incremental list
> traversal.
> 
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> ---
>   include/qemu/queue.h |   12 ++++++++++++
>   1 file changed, 12 insertions(+)
> 
> diff --git a/include/qemu/queue.h b/include/qemu/queue.h
> index 35292c3155..eb2bf9cb1c 100644
> --- a/include/qemu/queue.h
> +++ b/include/qemu/queue.h
> @@ -415,6 +415,18 @@ struct {                                                                \
>                   (var);                                                  \
>                   (var) = ((var)->field.tqe_next))
>   
> +/**
> + * QTAILQ_FOREACH_CONTINUE:
> + * @var: Variable to resume iteration from.
> + * @field: Field in @var holding a QTAILQ_ENTRY for this queue.
> + *
> + * Resumes iteration on a queue from the element in @var.
> + */
> +#define QTAILQ_FOREACH_CONTINUE(var, field)                             \
> +        for ((var) = ((var)->field.tqe_next);                           \
> +                (var);                                                  \
> +                (var) = ((var)->field.tqe_next))
> +
>   #define QTAILQ_FOREACH_SAFE(var, head, field, next_var)                 \
>           for ((var) = ((head)->tqh_first);                               \
>                   (var) && ((next_var) = ((var)->field.tqe_next), 1);     \
> 
> 

I still say this isn't required if the breakpoint loop is better structured.


r~

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 2/6] queue: Add macro for incremental traversal
  2017-06-19 23:20   ` Richard Henderson
@ 2017-06-26 12:33     ` Lluís Vilanova
  2017-06-27  1:10       ` Richard Henderson
  0 siblings, 1 reply; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-26 12:33 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-devel, Paolo Bonzini, Peter Crosthwaite, Alex Bennée

Richard Henderson writes:

> On 06/12/2017 07:54 AM, Lluís Vilanova wrote:
>> Adds macro QTAILQ_FOREACH_CONTINUE to support incremental list
>> traversal.
>> 
>> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
>> ---
>> include/qemu/queue.h |   12 ++++++++++++
>> 1 file changed, 12 insertions(+)
>> 
>> diff --git a/include/qemu/queue.h b/include/qemu/queue.h
>> index 35292c3155..eb2bf9cb1c 100644
>> --- a/include/qemu/queue.h
>> +++ b/include/qemu/queue.h
>> @@ -415,6 +415,18 @@ struct {                                                                \
>> (var);                                                  \
>> (var) = ((var)->field.tqe_next))
>> +/**
>> + * QTAILQ_FOREACH_CONTINUE:
>> + * @var: Variable to resume iteration from.
>> + * @field: Field in @var holding a QTAILQ_ENTRY for this queue.
>> + *
>> + * Resumes iteration on a queue from the element in @var.
>> + */
>> +#define QTAILQ_FOREACH_CONTINUE(var, field)                             \
>> +        for ((var) = ((var)->field.tqe_next);                           \
>> +                (var);                                                  \
>> +                (var) = ((var)->field.tqe_next))
>> +
>> #define QTAILQ_FOREACH_SAFE(var, head, field, next_var)                 \
>> for ((var) = ((head)->tqh_first);                               \
>> (var) && ((next_var) = ((var)->field.tqe_next), 1);     \
>> 
>> 

> I still say this isn't required if the breakpoint loop is better structured.

I can embed the use of QTAILQ into translate-block.c, but I wanted to keep the
implementation of breakpoint lists hidden behind the cpu_breakpoint API.


Thanks,
  Lluis

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 2/6] queue: Add macro for incremental traversal
  2017-06-26 12:33     ` Lluís Vilanova
@ 2017-06-27  1:10       ` Richard Henderson
  2017-06-27  9:13         ` Lluís Vilanova
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Henderson @ 2017-06-27  1:10 UTC (permalink / raw)
  To: qemu-devel, Paolo Bonzini, Peter Crosthwaite, Alex Bennée

On 06/26/2017 05:33 AM, Lluís Vilanova wrote:
> Richard Henderson writes:
> 
>> On 06/12/2017 07:54 AM, Lluís Vilanova wrote:
>>> Adds macro QTAILQ_FOREACH_CONTINUE to support incremental list
>>> traversal.
>>>
>>> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
>>> ---
>>> include/qemu/queue.h |   12 ++++++++++++
>>> 1 file changed, 12 insertions(+)
>>>
>>> diff --git a/include/qemu/queue.h b/include/qemu/queue.h
>>> index 35292c3155..eb2bf9cb1c 100644
>>> --- a/include/qemu/queue.h
>>> +++ b/include/qemu/queue.h
>>> @@ -415,6 +415,18 @@ struct {                                                                \
>>> (var);                                                  \
>>> (var) = ((var)->field.tqe_next))
>>> +/**
>>> + * QTAILQ_FOREACH_CONTINUE:
>>> + * @var: Variable to resume iteration from.
>>> + * @field: Field in @var holding a QTAILQ_ENTRY for this queue.
>>> + *
>>> + * Resumes iteration on a queue from the element in @var.
>>> + */
>>> +#define QTAILQ_FOREACH_CONTINUE(var, field)                             \
>>> +        for ((var) = ((var)->field.tqe_next);                           \
>>> +                (var);                                                  \
>>> +                (var) = ((var)->field.tqe_next))
>>> +
>>> #define QTAILQ_FOREACH_SAFE(var, head, field, next_var)                 \
>>> for ((var) = ((head)->tqh_first);                               \
>>> (var) && ((next_var) = ((var)->field.tqe_next), 1);     \
>>>
>>>
> 
>> I still say this isn't required if the breakpoint loop is better structured.
> 
> I can embed the use of QTAILQ into translate-block.c, but I wanted to keep the
> implementation of breakpoint lists hidden behind the cpu_breakpoint API.

I think using QTAILQ in the common main loop is better than twisting the logic 
so that the loop is unnaturally split into a subroutine.


r~

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v6 2/6] queue: Add macro for incremental traversal
  2017-06-27  1:10       ` Richard Henderson
@ 2017-06-27  9:13         ` Lluís Vilanova
  0 siblings, 0 replies; 34+ messages in thread
From: Lluís Vilanova @ 2017-06-27  9:13 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-devel, Paolo Bonzini, Peter Crosthwaite, Alex Bennée

Richard Henderson writes:

> On 06/26/2017 05:33 AM, Lluís Vilanova wrote:
>> Richard Henderson writes:
>> 
>>> On 06/12/2017 07:54 AM, Lluís Vilanova wrote:
>>>> Adds macro QTAILQ_FOREACH_CONTINUE to support incremental list
>>>> traversal.
>>>> 
>>>> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
>>>> ---
>>>> include/qemu/queue.h |   12 ++++++++++++
>>>> 1 file changed, 12 insertions(+)
>>>> 
>>>> diff --git a/include/qemu/queue.h b/include/qemu/queue.h
>>>> index 35292c3155..eb2bf9cb1c 100644
>>>> --- a/include/qemu/queue.h
>>>> +++ b/include/qemu/queue.h
>>>> @@ -415,6 +415,18 @@ struct {                                                                \
>>>> (var);                                                  \
>>>> (var) = ((var)->field.tqe_next))
>>>> +/**
>>>> + * QTAILQ_FOREACH_CONTINUE:
>>>> + * @var: Variable to resume iteration from.
>>>> + * @field: Field in @var holding a QTAILQ_ENTRY for this queue.
>>>> + *
>>>> + * Resumes iteration on a queue from the element in @var.
>>>> + */
>>>> +#define QTAILQ_FOREACH_CONTINUE(var, field)                             \
>>>> +        for ((var) = ((var)->field.tqe_next);                           \
>>>> +                (var);                                                  \
>>>> +                (var) = ((var)->field.tqe_next))
>>>> +
>>>> #define QTAILQ_FOREACH_SAFE(var, head, field, next_var)                 \
>>>> for ((var) = ((head)->tqh_first);                               \
>>>> (var) && ((next_var) = ((var)->field.tqe_next), 1);     \
>>>> 
>>>> 
>> 
>>> I still say this isn't required if the breakpoint loop is better structured.
>> 
>> I can embed the use of QTAILQ into translate-block.c, but I wanted to keep the
>> implementation of breakpoint lists hidden behind the cpu_breakpoint API.

> I think using QTAILQ in the common main loop is better than twisting the logic
> so that the loop is unnaturally split into a subroutine.

Ok, then I'll integrate that into the new series.

Thanks,
  Lluis

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2017-06-27  9:13 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-12 14:53 [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic translation framework Lluís Vilanova
2017-06-12 14:53 ` [Qemu-devel] [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
2017-06-13  1:40   ` David Gibson
2017-06-14 21:35   ` Eduardo Habkost
2017-06-14 22:30   ` Laurent Vivier
2017-06-16 14:07   ` Alex Bennée
2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 2/6] queue: Add macro for incremental traversal Lluís Vilanova
2017-06-19 23:20   ` Richard Henderson
2017-06-26 12:33     ` Lluís Vilanova
2017-06-27  1:10       ` Richard Henderson
2017-06-27  9:13         ` Lluís Vilanova
2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework Lluís Vilanova
2017-06-15 22:05   ` [Qemu-devel] [PATCH] translator mega-patch Emilio G. Cota
2017-06-18 14:37     ` Lluís Vilanova
2017-06-18 18:26       ` Peter Maydell
2017-06-19  4:08       ` Emilio G. Cota
2017-06-19  7:15         ` Peter Maydell
2017-06-15 22:19   ` [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework Emilio G. Cota
2017-06-15 23:25     ` Emilio G. Cota
2017-06-17  1:09       ` Emilio G. Cota
2017-06-18 14:24         ` Lluís Vilanova
2017-06-18 14:22       ` Lluís Vilanova
2017-06-18 15:47         ` Lluís Vilanova
2017-06-18 21:54           ` Lluís Vilanova
2017-06-19  4:10             ` Emilio G. Cota
2017-06-19  8:37               ` Lluís Vilanova
2017-06-18 14:20     ` Lluís Vilanova
2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 4/6] target: [tcg] Redefine DISAS_* onto the generic translation framework (DJ_*) Lluís Vilanova
2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 6/6] target: [tcg, arm] Port to generic translation framework Lluís Vilanova
2017-06-16  0:18   ` Emilio G. Cota
2017-06-18 14:41     ` Lluís Vilanova
2017-06-19  4:22       ` Emilio G. Cota
2017-06-15 18:02 ` [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic " Emilio G. Cota
2017-06-18 14:41   ` Lluís Vilanova

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.