Patchwork [RFC,qom-cpu,03/41] cpu: Turn cpu_get_tb_cpu_state() into a CPUClass hook

login
register
mail settings
Submitter Andreas Färber
Date Sept. 4, 2013, 9:04 a.m.
Message ID <1378285521-3230-4-git-send-email-afaerber@suse.de>
Download mbox | patch
Permalink /patch/272510/
State New
Headers show

Comments

Andreas Färber - Sept. 4, 2013, 9:04 a.m.
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 cpu-exec.c                  |  6 ++++--
 exec.c                      | 10 ++++++----
 hw/i386/kvmvapic.c          |  8 +++++---
 include/qom/cpu.h           |  4 ++++
 target-alpha/cpu.c          | 24 ++++++++++++++++++++++++
 target-alpha/cpu.h          | 21 ---------------------
 target-arm/cpu.c            | 28 ++++++++++++++++++++++++++++
 target-arm/cpu.h            | 24 ------------------------
 target-cris/cpu.c           | 14 ++++++++++++++
 target-cris/cpu.h           | 10 ----------
 target-i386/cpu.c           | 13 +++++++++++++
 target-i386/cpu.h           |  9 ---------
 target-lm32/cpu.c           | 11 +++++++++++
 target-lm32/cpu.h           |  9 ---------
 target-m68k/cpu.c           | 14 ++++++++++++++
 target-m68k/cpu.h           | 11 -----------
 target-microblaze/cpu.c     | 13 +++++++++++++
 target-microblaze/cpu.h     |  9 ---------
 target-mips/cpu.c           | 12 ++++++++++++
 target-mips/cpu.h           |  8 --------
 target-moxie/cpu.c          | 11 +++++++++++
 target-moxie/cpu.h          |  8 --------
 target-openrisc/cpu.c       | 12 ++++++++++++
 target-openrisc/cpu.h       | 10 ----------
 target-ppc/cpu.h            |  8 --------
 target-ppc/translate_init.c | 11 +++++++++++
 target-s390x/cpu.c          | 13 +++++++++++++
 target-s390x/cpu.h          |  9 ---------
 target-sh4/cpu.c            | 17 +++++++++++++++++
 target-sh4/cpu.h            | 13 -------------
 target-sparc/cpu.c          | 31 +++++++++++++++++++++++++++++++
 target-sparc/cpu.h          | 27 ---------------------------
 target-unicore32/cpu.c      | 14 ++++++++++++++
 target-unicore32/cpu.h      | 11 -----------
 target-xtensa/cpu.c         | 34 ++++++++++++++++++++++++++++++++++
 target-xtensa/cpu.h         | 30 ------------------------------
 translate-all.c             | 18 ++++++++++++------
 37 files changed, 303 insertions(+), 232 deletions(-)
Paolo Bonzini - Sept. 4, 2013, 10:26 a.m.
Il 04/09/2013 11:04, Andreas Färber ha scritto:
>  static inline TranslationBlock *tb_find_fast(CPUArchState *env)
>  {
> +    CPUState *cpu = ENV_GET_CPU(env);
> +    CPUClass *cc = CPU_GET_CLASS(cpu);
>      TranslationBlock *tb;
> -    target_ulong cs_base, pc;
> +    vaddr cs_base, pc;
>      int flags;
>  
>      /* we record a subset of the CPU state. It will
>         always be the same before a given translated block
>         is executed. */
> -    cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
> +    cc->get_tb_cpu_state(cpu, &pc, &cs_base, &flags);

I'm afraid you cannot turn inline functions into indirect calls like
this in hot paths.

One alternative would be to hoist the function call to the beginning of
cpu_exec, and ensure that any place that modifies the result calls
cpu_exit.  It may be a problem for SPARC's npc stuff, for which I have
no idea how it works.

Another is to change cpu-exec.c into a file that is #included by
target-*/helper.c or something like that.  This way cpu-exec.c can still
use the inline functions.

Paolo
Andreas Färber - Sept. 4, 2013, 11:02 a.m.
Am 04.09.2013 12:26, schrieb Paolo Bonzini:
> Il 04/09/2013 11:04, Andreas Färber ha scritto:
>>  static inline TranslationBlock *tb_find_fast(CPUArchState *env)
>>  {
>> +    CPUState *cpu = ENV_GET_CPU(env);
>> +    CPUClass *cc = CPU_GET_CLASS(cpu);
>>      TranslationBlock *tb;
>> -    target_ulong cs_base, pc;
>> +    vaddr cs_base, pc;
>>      int flags;
>>  
>>      /* we record a subset of the CPU state. It will
>>         always be the same before a given translated block
>>         is executed. */
>> -    cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
>> +    cc->get_tb_cpu_state(cpu, &pc, &cs_base, &flags);
> 
> I'm afraid you cannot turn inline functions into indirect calls like
> this in hot paths.
> 
> One alternative would be to hoist the function call to the beginning of
> cpu_exec, and ensure that any place that modifies the result calls
> cpu_exit.  It may be a problem for SPARC's npc stuff, for which I have
> no idea how it works.

Sorry, you lost me here...

> Another is to change cpu-exec.c into a file that is #included by
> target-*/helper.c or something like that.  This way cpu-exec.c can still
> use the inline functions.

I don't see how that would help with compiling multiple CPU types into
one executable. A common CPU struct type is needed to compile the core
CPU code once, which in turn requires dispatching for target-specific
bits, such as this one or previously gdbstub and TBD monitor.

Combining only targets with target_ulong of the same size and identical
endianness is a restriction we can accept, I think - examples include
32-bit ARM+SH4A, ARM+MicroBlaze, ARM+Hexagon, ARM+Epiphany.

For performance reasons I have been careful not to have an, e.g.,
cpu_get_tb_cpu_state() wrapper that calls CPU_GET_CLASS() each time.
Many of the "cpu" variables added are being cleaned up later in the
series by argument propagation. And in placement of variables requiring
CPU() cast I have been careful to place them depending on where they
are/will be actually used rather than always placing them at the top.
But if behavior depends on the CPU type, then it cannot be a global
function - cpu.h as-is is a problem and needs to be broken up.

Andreas
Paolo Bonzini - Sept. 4, 2013, 11:20 a.m.
Il 04/09/2013 13:02, Andreas Färber ha scritto:
> Am 04.09.2013 12:26, schrieb Paolo Bonzini:
>> Another is to change cpu-exec.c into a file that is #included by
>> target-*/helper.c or something like that.  This way cpu-exec.c can still
>> use the inline functions.
> 
> I don't see how that would help with compiling multiple CPU types into
> one executable.
> 
> A common CPU struct type is needed to compile the core
> CPU code once, which in turn requires dispatching for target-specific
> bits, such as this one or previously gdbstub and TBD monitor.

cpu-exec.c is all but common to the various targets.  You could make
cpu_exec() itself a CPU method.  Then calls to cpu_get_tb_cpu_state()
from cpu_exec() can remain inlined instead of being virtual calls.

Not all files have to be compiled "per target", probably only cputlb.c
and cpu-exec.c.

Paolo

> Combining only targets with target_ulong of the same size and identical
> endianness is a restriction we can accept, I think - examples include
> 32-bit ARM+SH4A, ARM+MicroBlaze, ARM+Hexagon, ARM+Epiphany.
> 
> For performance reasons I have been careful not to have an, e.g.,
> cpu_get_tb_cpu_state() wrapper that calls CPU_GET_CLASS() each time.
> Many of the "cpu" variables added are being cleaned up later in the
> series by argument propagation. And in placement of variables requiring
> CPU() cast I have been careful to place them depending on where they
> are/will be actually used rather than always placing them at the top.
> But if behavior depends on the CPU type, then it cannot be a global
> function - cpu.h as-is is a problem and needs to be broken up.
> 
> Andreas
>

Patch

diff --git a/cpu-exec.c b/cpu-exec.c
index e9866b8..c839f80 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -153,14 +153,16 @@  static TranslationBlock *tb_find_slow(CPUArchState *env,
 
 static inline TranslationBlock *tb_find_fast(CPUArchState *env)
 {
+    CPUState *cpu = ENV_GET_CPU(env);
+    CPUClass *cc = CPU_GET_CLASS(cpu);
     TranslationBlock *tb;
-    target_ulong cs_base, pc;
+    vaddr cs_base, pc;
     int flags;
 
     /* we record a subset of the CPU state. It will
        always be the same before a given translated block
        is executed. */
-    cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
+    cc->get_tb_cpu_state(cpu, &pc, &cs_base, &flags);
     tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
     if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
                  tb->flags != flags)) {
diff --git a/exec.c b/exec.c
index 87b0b39..4354eac 100644
--- a/exec.c
+++ b/exec.c
@@ -1478,8 +1478,10 @@  static const MemoryRegionOps notdirty_mem_ops = {
 /* Generate a debug exception if a watchpoint has been hit.  */
 static void check_watchpoint(int offset, int len_mask, int flags)
 {
-    CPUArchState *env = current_cpu->env_ptr;
-    target_ulong pc, cs_base;
+    CPUState *cpu = current_cpu;
+    CPUArchState *env = cpu->env_ptr;
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+    vaddr pc, cs_base;
     target_ulong vaddr;
     CPUWatchpoint *wp;
     int cpu_flags;
@@ -1488,7 +1490,7 @@  static void check_watchpoint(int offset, int len_mask, int flags)
         /* We re-entered the check after replacing the TB. Now raise
          * the debug interrupt so that is will trigger after the
          * current instruction. */
-        cpu_interrupt(ENV_GET_CPU(env), CPU_INTERRUPT_DEBUG);
+        cpu_interrupt(cpu, CPU_INTERRUPT_DEBUG);
         return;
     }
     vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
@@ -1503,7 +1505,7 @@  static void check_watchpoint(int offset, int len_mask, int flags)
                     env->exception_index = EXCP_DEBUG;
                     cpu_loop_exit(env);
                 } else {
-                    cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
+                    cc->get_tb_cpu_state(cpu, &pc, &cs_base, &cpu_flags);
                     tb_gen_code(env, pc, cs_base, cpu_flags, 1);
                     cpu_resume_from_signal(env, NULL);
                 }
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index d3a6fbe..7295e5b 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -395,8 +395,8 @@  static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
     VAPICHandlers *handlers;
     uint8_t opcode[2];
     uint32_t imm32;
-    target_ulong current_pc = 0;
-    target_ulong current_cs_base = 0;
+    vaddr current_pc = 0;
+    vaddr current_cs_base = 0;
     int current_flags = 0;
 
     if (smp_cpus == 1) {
@@ -406,8 +406,10 @@  static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
     }
 
     if (!kvm_enabled()) {
+        CPUClass *cc = CPU_GET_CLASS(cs);
+
         cpu_restore_state(env, env->mem_io_pc);
-        cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
+        cc->get_tb_cpu_state(cs, &current_pc, &current_cs_base,
                              &current_flags);
     }
 
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index c78d572..3d6b66e 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -80,6 +80,8 @@  struct TranslationBlock;
  * @get_paging_enabled: Callback for inquiring whether paging is enabled.
  * @get_memory_mapping: Callback for obtaining the memory mappings.
  * @set_pc: Callback for setting the Program Counter register.
+ * @get_tb_cpu_state: Callback for obtaining state for a TCG
+ * #TranslationBlock.
  * @synchronize_from_tb: Callback for synchronizing state from a TCG
  * #TranslationBlock.
  * @get_phys_page_debug: Callback for obtaining a physical address.
@@ -115,6 +117,8 @@  typedef struct CPUClass {
     void (*get_memory_mapping)(CPUState *cpu, MemoryMappingList *list,
                                Error **errp);
     void (*set_pc)(CPUState *cpu, vaddr value);
+    void (*get_tb_cpu_state)(const CPUState *cpu, vaddr *pc, vaddr *cs_base,
+                             int *flags);
     void (*synchronize_from_tb)(CPUState *cpu, struct TranslationBlock *tb);
     hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr);
     int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c
index 15d6f1f..bb1eddc 100644
--- a/target-alpha/cpu.c
+++ b/target-alpha/cpu.c
@@ -31,6 +31,29 @@  static void alpha_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.pc = value;
 }
 
+static void alpha_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                       vaddr *cs_base, int *pflags)
+{
+    AlphaCPU *cpu = ALPHA_CPU(cs);
+    CPUAlphaState *env = &cpu->env;
+    int flags = 0;
+
+    *pc = env->pc;
+    *cs_base = 0;
+
+    if (env->pal_mode) {
+        flags = TB_FLAGS_PAL_MODE;
+    } else {
+        flags = env->ps & PS_USER_MODE;
+    }
+    if (env->fen) {
+        flags |= TB_FLAGS_FEN;
+    }
+    flags |= env->amask << TB_FLAGS_AMASK_SHIFT;
+
+    *pflags = flags;
+}
+
 static int alpha_cpu_mmu_index(const CPUState *cs)
 {
     AlphaCPU *cpu = ALPHA_CPU(cs);
@@ -304,6 +327,7 @@  static void alpha_cpu_class_init(ObjectClass *oc, void *data)
     cc->dump_state = alpha_cpu_dump_state;
     cc->mmu_index = alpha_cpu_mmu_index;
     cc->set_pc = alpha_cpu_set_pc;
+    cc->get_tb_cpu_state = alpha_cpu_get_tb_cpu_state;
     cc->gdb_read_register = alpha_cpu_gdb_read_register;
     cc->gdb_write_register = alpha_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 808fe53..a4abce8 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -466,27 +466,6 @@  enum {
     TB_FLAGS_AMASK_PREFETCH = AMASK_PREFETCH << TB_FLAGS_AMASK_SHIFT,
 };
 
-static inline void cpu_get_tb_cpu_state(CPUAlphaState *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *pflags)
-{
-    int flags = 0;
-
-    *pc = env->pc;
-    *cs_base = 0;
-
-    if (env->pal_mode) {
-        flags = TB_FLAGS_PAL_MODE;
-    } else {
-        flags = env->ps & PS_USER_MODE;
-    }
-    if (env->fen) {
-        flags |= TB_FLAGS_FEN;
-    }
-    flags |= env->amask << TB_FLAGS_AMASK_SHIFT;
-
-    *pflags = flags;
-}
-
 #include "exec/exec-all.h"
 
 #endif /* !defined (__CPU_ALPHA_H__) */
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 6032a2c..53bf337 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -34,6 +34,33 @@  static void arm_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.regs[15] = value;
 }
 
+static void arm_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                     vaddr *cs_base, int *flags)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    int privmode;
+
+    *pc = env->regs[15];
+    *cs_base = 0;
+    *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
+           | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
+           | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
+           | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
+           | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
+    if (arm_feature(env, ARM_FEATURE_M)) {
+        privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
+    } else {
+        privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
+    }
+    if (privmode) {
+        *flags |= ARM_TBFLAG_PRIV_MASK;
+    }
+    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
+        *flags |= ARM_TBFLAG_VFPEN_MASK;
+    }
+}
+
 static int arm_cpu_mmu_index(const CPUState *cs)
 {
     ARMCPU *cpu = ARM_CPU(cs);
@@ -908,6 +935,7 @@  static void arm_cpu_class_init(ObjectClass *oc, void *data)
     cc->dump_state = arm_cpu_dump_state;
     cc->mmu_index = arm_cpu_mmu_index;
     cc->set_pc = arm_cpu_set_pc;
+    cc->get_tb_cpu_state = arm_cpu_get_tb_cpu_state;
     cc->gdb_read_register = arm_cpu_gdb_read_register;
     cc->gdb_write_register = arm_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 19fa4ee..161b9fd 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -786,30 +786,6 @@  static inline CPUARMState *cpu_init(const char *cpu_model)
 #define ARM_TBFLAG_BSWAP_CODE(F) \
     (((F) & ARM_TBFLAG_BSWAP_CODE_MASK) >> ARM_TBFLAG_BSWAP_CODE_SHIFT)
 
-static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    int privmode;
-    *pc = env->regs[15];
-    *cs_base = 0;
-    *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
-        | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
-        | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
-        | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
-        | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
-    if (arm_feature(env, ARM_FEATURE_M)) {
-        privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
-    } else {
-        privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
-    }
-    if (privmode) {
-        *flags |= ARM_TBFLAG_PRIV_MASK;
-    }
-    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
-        *flags |= ARM_TBFLAG_VFPEN_MASK;
-    }
-}
-
 #include "exec/exec-all.h"
 
 /* Load an instruction and return it in the standard little-endian order */
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index 1e5b425..39a25ed 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -33,6 +33,19 @@  static void cris_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.pc = value;
 }
 
+static void cris_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                      vaddr *cs_base, int *flags)
+{
+    CRISCPU *cpu = CRIS_CPU(cs);
+    CPUCRISState *env = &cpu->env;
+
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = env->dslot |
+            (env->pregs[PR_CCS] & (S_FLAG | P_FLAG | U_FLAG |
+                                   X_FLAG | PFIX_FLAG));
+}
+
 static int cris_cpu_mmu_index(const CPUState *cs)
 {
     CRISCPU *cpu = CRIS_CPU(cs);
@@ -274,6 +287,7 @@  static void cris_cpu_class_init(ObjectClass *oc, void *data)
     cc->dump_state = cris_cpu_dump_state;
     cc->mmu_index = cris_cpu_mmu_index;
     cc->set_pc = cris_cpu_set_pc;
+    cc->get_tb_cpu_state = cris_cpu_get_tb_cpu_state;
     cc->gdb_read_register = cris_cpu_gdb_read_register;
     cc->gdb_write_register = cris_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index 0914103..9f1fa38 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -255,16 +255,6 @@  int cpu_cris_handle_mmu_fault(CPUCRISState *env, target_ulong address, int rw,
 
 #include "exec/cpu-all.h"
 
-static inline void cpu_get_tb_cpu_state(CPUCRISState *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->pc;
-    *cs_base = 0;
-    *flags = env->dslot |
-            (env->pregs[PR_CCS] & (S_FLAG | P_FLAG | U_FLAG
-				     | X_FLAG | PFIX_FLAG));
-}
-
 #define cpu_list cris_cpu_list
 void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index a623383..995d5ff 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -2669,6 +2669,18 @@  static void x86_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.eip = value;
 }
 
+static void x86_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                     vaddr *cs_base, int *flags)
+{
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
+
+    *cs_base = env->segs[R_CS].base;
+    *pc = *cs_base + env->eip;
+    *flags = env->hflags |
+        (env->eflags & (IOPL_MASK | TF_MASK | RF_MASK | VM_MASK | AC_MASK));
+}
+
 static void x86_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
 {
     X86CPU *cpu = X86_CPU(cs);
@@ -2725,6 +2737,7 @@  static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
     cc->dump_state = x86_cpu_dump_state;
     cc->mmu_index = x86_cpu_mmu_index;
     cc->set_pc = x86_cpu_set_pc;
+    cc->get_tb_cpu_state = x86_cpu_get_tb_cpu_state;
     cc->synchronize_from_tb = x86_cpu_synchronize_from_tb;
     cc->gdb_read_register = x86_cpu_gdb_read_register;
     cc->gdb_write_register = x86_cpu_gdb_write_register;
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index fd16f20..999a46c 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -1157,15 +1157,6 @@  void optimize_flags_init(void);
 
 #include "exec/exec-all.h"
 
-static inline void cpu_get_tb_cpu_state(CPUX86State *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *cs_base = env->segs[R_CS].base;
-    *pc = *cs_base + env->eip;
-    *flags = env->hflags |
-        (env->eflags & (IOPL_MASK | TF_MASK | RF_MASK | VM_MASK | AC_MASK));
-}
-
 void do_cpu_init(X86CPU *cpu);
 void do_cpu_sipi(X86CPU *cpu);
 
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
index 4fa8605..7976d39 100644
--- a/target-lm32/cpu.c
+++ b/target-lm32/cpu.c
@@ -29,6 +29,16 @@  static void lm32_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.pc = value;
 }
 
+static void lm32_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                      vaddr *cs_base, int *flags)
+{
+    LM32CPU *cpu = LM32_CPU(cs);
+
+    *pc = cpu->env.pc;
+    *cs_base = 0;
+    *flags = 0;
+}
+
 static bool lm32_cpu_has_work(CPUState *cs)
 {
     return cs->interrupt_request & CPU_INTERRUPT_HARD;
@@ -95,6 +105,7 @@  static void lm32_cpu_class_init(ObjectClass *oc, void *data)
     cc->do_interrupt = lm32_cpu_do_interrupt;
     cc->dump_state = lm32_cpu_dump_state;
     cc->set_pc = lm32_cpu_set_pc;
+    cc->get_tb_cpu_state = lm32_cpu_get_tb_cpu_state;
     cc->gdb_read_register = lm32_cpu_gdb_read_register;
     cc->gdb_write_register = lm32_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
index 11f54e7..a34f047 100644
--- a/target-lm32/cpu.h
+++ b/target-lm32/cpu.h
@@ -212,15 +212,6 @@  int cpu_lm32_handle_mmu_fault(CPULM32State *env, target_ulong address, int rw,
 #define cpu_handle_mmu_fault cpu_lm32_handle_mmu_fault
 
 #include "exec/cpu-all.h"
-
-static inline void cpu_get_tb_cpu_state(CPULM32State *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->pc;
-    *cs_base = 0;
-    *flags = 0;
-}
-
 #include "exec/exec-all.h"
 
 #endif
diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c
index 00454ab..6dbfe89 100644
--- a/target-m68k/cpu.c
+++ b/target-m68k/cpu.c
@@ -30,6 +30,19 @@  static void m68k_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.pc = value;
 }
 
+static void m68k_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                      vaddr *cs_base, int *flags)
+{
+    M68kCPU *cpu = M68K_CPU(cs);
+    CPUM68KState *env = &cpu->env;
+
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = (env->fpcr & M68K_FPCR_PREC)       /* Bit  6 */
+            | (env->sr & SR_S)                  /* Bit  13 */
+            | ((env->macsr >> 4) & 0xf);        /* Bits 0-3 */
+}
+
 static int m68k_cpu_mmu_index(const CPUState *cs)
 {
     M68kCPU *cpu = M68K_CPU(cs);
@@ -206,6 +219,7 @@  static void m68k_cpu_class_init(ObjectClass *c, void *data)
     cc->dump_state = m68k_cpu_dump_state;
     cc->mmu_index = m68k_cpu_mmu_index;
     cc->set_pc = m68k_cpu_set_pc;
+    cc->get_tb_cpu_state = m68k_cpu_get_tb_cpu_state;
     cc->gdb_read_register = m68k_cpu_gdb_read_register;
     cc->gdb_write_register = m68k_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index d1291d8..5c7992e 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -238,17 +238,6 @@  int cpu_m68k_handle_mmu_fault(CPUM68KState *env, target_ulong address, int rw,
 #define cpu_handle_mmu_fault cpu_m68k_handle_mmu_fault
 
 #include "exec/cpu-all.h"
-
-static inline void cpu_get_tb_cpu_state(CPUM68KState *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->pc;
-    *cs_base = 0;
-    *flags = (env->fpcr & M68K_FPCR_PREC)       /* Bit  6 */
-            | (env->sr & SR_S)                  /* Bit  13 */
-            | ((env->macsr >> 4) & 0xf);        /* Bits 0-3 */
-}
-
 #include "exec/exec-all.h"
 
 #endif
diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
index 929efd8..fbcdcc4 100644
--- a/target-microblaze/cpu.c
+++ b/target-microblaze/cpu.c
@@ -33,6 +33,18 @@  static void mb_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.sregs[SR_PC] = value;
 }
 
+static void mb_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                    vaddr *cs_base, int *flags)
+{
+    MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+    CPUMBState *env = &cpu->env;
+
+    *pc = env->sregs[SR_PC];
+    *cs_base = 0;
+    *flags = (env->iflags & IFLAGS_TB_MASK) |
+             (env->sregs[SR_MSR] & (MSR_UM | MSR_VM | MSR_EE));
+}
+
 static int mb_cpu_mmu_index(const CPUState *cs)
 {
     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
@@ -163,6 +175,7 @@  static void mb_cpu_class_init(ObjectClass *oc, void *data)
     cc->dump_state = mb_cpu_dump_state;
     cc->mmu_index = mb_cpu_mmu_index;
     cc->set_pc = mb_cpu_set_pc;
+    cc->get_tb_cpu_state = mb_cpu_get_tb_cpu_state;
     cc->gdb_read_register = mb_cpu_gdb_read_register;
     cc->gdb_write_register = mb_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index a81f899..d80f812 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -332,15 +332,6 @@  static inline target_ulong cpu_get_pc(CPUMBState *env)
     return env->sregs[SR_PC];
 }
 
-static inline void cpu_get_tb_cpu_state(CPUMBState *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->sregs[SR_PC];
-    *cs_base = 0;
-    *flags = (env->iflags & IFLAGS_TB_MASK) |
-                 (env->sregs[SR_MSR] & (MSR_UM | MSR_VM | MSR_EE));
-}
-
 #if !defined(CONFIG_USER_ONLY)
 void mb_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
                               bool is_write, bool is_exec, int is_asi,
diff --git a/target-mips/cpu.c b/target-mips/cpu.c
index cb916f3..4aa06bb 100644
--- a/target-mips/cpu.c
+++ b/target-mips/cpu.c
@@ -35,6 +35,17 @@  static void mips_cpu_set_pc(CPUState *cs, vaddr value)
     }
 }
 
+static void mips_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                      vaddr *cs_base, int *flags)
+{
+    MIPSCPU *cpu = MIPS_CPU(cs);
+    CPUMIPSState *env = &cpu->env;
+
+    *pc = env->active_tc.PC;
+    *cs_base = 0;
+    *flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
+}
+
 static void mips_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
 {
     MIPSCPU *cpu = MIPS_CPU(cs);
@@ -138,6 +149,7 @@  static void mips_cpu_class_init(ObjectClass *c, void *data)
     cc->dump_state = mips_cpu_dump_state;
     cc->mmu_index = mips_cpu_mmu_index;
     cc->set_pc = mips_cpu_set_pc;
+    cc->get_tb_cpu_state = mips_cpu_get_tb_cpu_state;
     cc->synchronize_from_tb = mips_cpu_synchronize_from_tb;
     cc->gdb_read_register = mips_cpu_gdb_read_register;
     cc->gdb_write_register = mips_cpu_gdb_write_register;
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 22643ff..91217ed 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -659,14 +659,6 @@  hwaddr cpu_mips_translate_address (CPUMIPSState *env, target_ulong address,
 #endif
 target_ulong exception_resume_pc (CPUMIPSState *env);
 
-static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->active_tc.PC;
-    *cs_base = 0;
-    *flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
-}
-
 static inline int mips_vpe_active(CPUMIPSState *env)
 {
     int active = 1;
diff --git a/target-moxie/cpu.c b/target-moxie/cpu.c
index 66f337e..9983c99 100644
--- a/target-moxie/cpu.c
+++ b/target-moxie/cpu.c
@@ -29,6 +29,16 @@  static void moxie_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.pc = value;
 }
 
+static void moxie_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                       vaddr *cs_base, int *flags)
+{
+    MoxieCPU *cpu = MOXIE_CPU(cs);
+
+    *pc = cpu->env.pc;
+    *cs_base = 0;
+    *flags = 0;
+}
+
 static bool moxie_cpu_has_work(CPUState *cs)
 {
     return cs->interrupt_request & CPU_INTERRUPT_HARD;
@@ -108,6 +118,7 @@  static void moxie_cpu_class_init(ObjectClass *oc, void *data)
     cc->do_interrupt = moxie_cpu_do_interrupt;
     cc->dump_state = moxie_cpu_dump_state;
     cc->set_pc = moxie_cpu_set_pc;
+    cc->get_tb_cpu_state = moxie_cpu_get_tb_cpu_state;
 #ifndef CONFIG_USER_ONLY
     cc->get_phys_page_debug = moxie_cpu_get_phys_page_debug;
     cc->vmsd = &vmstate_moxie_cpu;
diff --git a/target-moxie/cpu.h b/target-moxie/cpu.h
index affcfca..7e33efe 100644
--- a/target-moxie/cpu.h
+++ b/target-moxie/cpu.h
@@ -139,14 +139,6 @@  static inline CPUMoxieState *cpu_init(const char *cpu_model)
 #include "exec/cpu-all.h"
 #include "exec/exec-all.h"
 
-static inline void cpu_get_tb_cpu_state(CPUMoxieState *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->pc;
-    *cs_base = 0;
-    *flags = 0;
-}
-
 int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
                                int rw, int mmu_idx);
 
diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c
index 4872fcf..107e5f9 100644
--- a/target-openrisc/cpu.c
+++ b/target-openrisc/cpu.c
@@ -27,6 +27,17 @@  static void openrisc_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.pc = value;
 }
 
+static void openrisc_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                          vaddr *cs_base, int *flags)
+{
+    OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+
+    *pc = cpu->env.pc;
+    *cs_base = 0;
+    /* D_FLAG -- branch instruction exception */
+    *flags = (cpu->env.flags & D_FLAG);
+}
+
 static int openrisc_cpu_mmu_index(const CPUState *cs)
 {
     OpenRISCCPU *cpu = OPENRISC_CPU(cs);
@@ -174,6 +185,7 @@  static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
     cc->dump_state = openrisc_cpu_dump_state;
     cc->mmu_index = openrisc_cpu_mmu_index;
     cc->set_pc = openrisc_cpu_set_pc;
+    cc->get_tb_cpu_state = openrisc_cpu_get_tb_cpu_state;
     cc->gdb_read_register = openrisc_cpu_gdb_read_register;
     cc->gdb_write_register = openrisc_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index 2a1ca92..a41c271 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -399,16 +399,6 @@  static inline CPUOpenRISCState *cpu_init(const char *cpu_model)
 
 #include "exec/cpu-all.h"
 
-static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env,
-                                        target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->pc;
-    *cs_base = 0;
-    /* D_FLAG -- branch instruction exception */
-    *flags = (env->flags & D_FLAG);
-}
-
 #define CPU_INTERRUPT_TIMER   CPU_INTERRUPT_TGT_INT_0
 
 #include "exec/exec-all.h"
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 9c99f0d..2ebf0a1 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -2015,14 +2015,6 @@  static inline void cpu_write_xer(CPUPPCState *env, target_ulong xer)
     env->xer = xer & ~((1u << XER_SO) | (1u << XER_OV) | (1u << XER_CA));
 }
 
-static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->nip;
-    *cs_base = 0;
-    *flags = env->hflags;
-}
-
 #if !defined(CONFIG_USER_ONLY)
 static inline int booke206_tlbm_id(CPUPPCState *env, ppcmas_tlb_t *tlbm)
 {
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index e4bcf74..338d8fe 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8437,6 +8437,16 @@  static void ppc_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.nip = value;
 }
 
+static void ppc_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                     vaddr *cs_base, int *flags)
+{
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+    *pc = cpu->env.nip;
+    *cs_base = 0;
+    *flags = cpu->env.hflags;
+}
+
 static int ppc_cpu_mmu_index(const CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -8582,6 +8592,7 @@  static void ppc_cpu_class_init(ObjectClass *oc, void *data)
     cc->dump_statistics = ppc_cpu_dump_statistics;
     cc->mmu_index = ppc_cpu_mmu_index;
     cc->set_pc = ppc_cpu_set_pc;
+    cc->get_tb_cpu_state = ppc_cpu_get_tb_cpu_state;
     cc->gdb_read_register = ppc_cpu_gdb_read_register;
     cc->gdb_write_register = ppc_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index 6b200fe..a4a5370 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -65,6 +65,18 @@  static void s390_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.psw.addr = value;
 }
 
+static void s390_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                      vaddr *cs_base, int *flags)
+{
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+
+    *pc = env->psw.addr;
+    *cs_base = 0;
+    *flags = ((env->psw.mask >> 32) & ~FLAG_MASK_CC) |
+             ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0);
+}
+
 static int s390_cpu_mmu_index(const CPUState *cs)
 {
     S390CPU *cpu = S390_CPU(cs);
@@ -242,6 +254,7 @@  static void s390_cpu_class_init(ObjectClass *oc, void *data)
     cc->dump_state = s390_cpu_dump_state;
     cc->mmu_index = s390_cpu_mmu_index;
     cc->set_pc = s390_cpu_set_pc;
+    cc->get_tb_cpu_state = s390_cpu_get_tb_cpu_state;
     cc->gdb_read_register = s390_cpu_gdb_read_register;
     cc->gdb_write_register = s390_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index d7970e6..cad092b 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -273,15 +273,6 @@  typedef struct CPUS390XState {
 #define FLAG_MASK_64            (PSW_MASK_64     >> 32)
 #define FLAG_MASK_32            0x00001000
 
-static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->psw.addr;
-    *cs_base = 0;
-    *flags = ((env->psw.mask >> 32) & ~FLAG_MASK_CC) |
-             ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0);
-}
-
 /* While the PoO talks about ILC (a number between 1-3) what is actually
    stored in LowCore is shifted left one bit (an even between 2-6).  As
    this is the actual length of the insn and therefore more useful, that
diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c
index df1c0e8..647a527 100644
--- a/target-sh4/cpu.c
+++ b/target-sh4/cpu.c
@@ -31,6 +31,22 @@  static void superh_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.pc = value;
 }
 
+static void superh_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                        vaddr *cs_base, int *flags)
+{
+    SuperHCPU *cpu = SUPERH_CPU(cs);
+    CPUSH4State *env = &cpu->env;
+
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL |
+                            DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME))  /* Bits 0-3 */
+           | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR))  /* Bits 19-21 */
+           | (env->sr & (SR_MD | SR_RB))                      /* Bits 29-30 */
+           | (env->sr & SR_FD)                                /* Bit 15 */
+           | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 4 */
+}
+
 static void superh_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
 {
     SuperHCPU *cpu = SUPERH_CPU(cs);
@@ -300,6 +316,7 @@  static void superh_cpu_class_init(ObjectClass *oc, void *data)
     cc->dump_state = superh_cpu_dump_state;
     cc->mmu_index = superh_cpu_mmu_index;
     cc->set_pc = superh_cpu_set_pc;
+    cc->get_tb_cpu_state = superh_cpu_get_tb_cpu_state;
     cc->synchronize_from_tb = superh_cpu_synchronize_from_tb;
     cc->gdb_read_register = superh_cpu_gdb_read_register;
     cc->gdb_write_register = superh_cpu_gdb_write_register;
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index 6125c20..42ecdd7 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -335,19 +335,6 @@  static inline int cpu_ptel_pr (uint32_t ptel)
 
 #define TB_FLAG_PENDING_MOVCA  (1 << 4)
 
-static inline void cpu_get_tb_cpu_state(CPUSH4State *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->pc;
-    *cs_base = 0;
-    *flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL
-                    | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME))   /* Bits  0- 3 */
-            | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR))  /* Bits 19-21 */
-            | (env->sr & (SR_MD | SR_RB))                      /* Bits 29-30 */
-            | (env->sr & SR_FD)                                /* Bit 15 */
-            | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 4 */
-}
-
 #include "exec/exec-all.h"
 
 #endif				/* _CPU_SH4_H */
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index 1d27f9e..49a4469 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -731,6 +731,36 @@  static void sparc_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.npc = value + 4;
 }
 
+static void sparc_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                       vaddr *cs_base, int *flags)
+{
+    SPARCCPU *cpu = SPARC_CPU(cs);
+    CPUSPARCState *env = &cpu->env;
+
+    *pc = env->pc;
+    *cs_base = env->npc;
+#ifdef TARGET_SPARC64
+    /* AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled */
+    *flags = (env->pstate & PS_PRIV)                  /* 2 */
+           | ((env->lsu & (DMMU_E | IMMU_E)) >> 2)    /* 1, 0 */
+           | ((env->tl & 0xff) << 8)
+           | (env->dmmu.mmu_primary_context << 16);   /* 16... */
+    if (env->pstate & PS_AM) {
+        *flags |= TB_FLAG_AM_ENABLED;
+    }
+    if ((env->def->features & CPU_FEATURE_FLOAT) && (env->pstate & PS_PEF)
+        && (env->fprs & FPRS_FEF)) {
+        *flags |= TB_FLAG_FPU_ENABLED;
+    }
+#else
+    /* FPU enable . Supervisor */
+    *flags = env->psrs;
+    if ((env->def->features & CPU_FEATURE_FLOAT) && env->psref) {
+        *flags |= TB_FLAG_FPU_ENABLED;
+    }
+#endif
+}
+
 static void sparc_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
 {
     SPARCCPU *cpu = SPARC_CPU(cs);
@@ -823,6 +853,7 @@  static void sparc_cpu_class_init(ObjectClass *oc, void *data)
 #endif
     cc->mmu_index = sparc_cpu_mmu_index;
     cc->set_pc = sparc_cpu_set_pc;
+    cc->get_tb_cpu_state = sparc_cpu_get_tb_cpu_state;
     cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
     cc->gdb_read_register = sparc_cpu_gdb_read_register;
     cc->gdb_write_register = sparc_cpu_gdb_write_register;
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 93590b8..f078851 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -683,33 +683,6 @@  trap_state* cpu_tsptr(CPUSPARCState* env);
 #define TB_FLAG_FPU_ENABLED (1 << 4)
 #define TB_FLAG_AM_ENABLED (1 << 5)
 
-static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->pc;
-    *cs_base = env->npc;
-#ifdef TARGET_SPARC64
-    // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
-    *flags = (env->pstate & PS_PRIV)               /* 2 */
-        | ((env->lsu & (DMMU_E | IMMU_E)) >> 2)    /* 1, 0 */
-        | ((env->tl & 0xff) << 8)
-        | (env->dmmu.mmu_primary_context << 16);   /* 16... */
-    if (env->pstate & PS_AM) {
-        *flags |= TB_FLAG_AM_ENABLED;
-    }
-    if ((env->def->features & CPU_FEATURE_FLOAT) && (env->pstate & PS_PEF)
-        && (env->fprs & FPRS_FEF)) {
-        *flags |= TB_FLAG_FPU_ENABLED;
-    }
-#else
-    // FPU enable . Supervisor
-    *flags = env->psrs;
-    if ((env->def->features & CPU_FEATURE_FLOAT) && env->psref) {
-        *flags |= TB_FLAG_FPU_ENABLED;
-    }
-#endif
-}
-
 static inline bool tb_fpu_enabled(int tb_flags)
 {
 #if defined(CONFIG_USER_ONLY)
diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c
index 3ed9ea3..e5fddcf 100644
--- a/target-unicore32/cpu.c
+++ b/target-unicore32/cpu.c
@@ -23,6 +23,19 @@  static void uc32_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.regs[31] = value;
 }
 
+static void uc32_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                      vaddr *cs_base, int *flags)
+{
+    UniCore32CPU *cpu = UNICORE32_CPU(cs);
+
+    *pc = cpu->env.regs[31];
+    *cs_base = 0;
+    *flags = 0;
+    if ((cpu->env.uncached_asr & ASR_M) != ASR_MODE_USER) {
+        *flags |= (1 << 6);
+    }
+}
+
 static int uc32_cpu_mmu_index(const CPUState *cs)
 {
     UniCore32CPU *cpu = UNICORE32_CPU(cs);
@@ -156,6 +169,7 @@  static void uc32_cpu_class_init(ObjectClass *oc, void *data)
     cc->dump_state = uc32_cpu_dump_state;
     cc->mmu_index = uc32_cpu_mmu_index;
     cc->set_pc = uc32_cpu_set_pc;
+    cc->get_tb_cpu_state = uc32_cpu_get_tb_cpu_state;
 #ifndef CONFIG_USER_ONLY
     cc->get_phys_page_debug = uc32_cpu_get_phys_page_debug;
 #endif
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
index 07693d5..75f5fa9 100644
--- a/target-unicore32/cpu.h
+++ b/target-unicore32/cpu.h
@@ -142,17 +142,6 @@  int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address, int
 #include "cpu-qom.h"
 #include "exec/exec-all.h"
 
-static inline void cpu_get_tb_cpu_state(CPUUniCore32State *env, target_ulong *pc,
-                                        target_ulong *cs_base, int *flags)
-{
-    *pc = env->regs[31];
-    *cs_base = 0;
-    *flags = 0;
-    if ((env->uncached_asr & ASR_M) != ASR_MODE_USER) {
-        *flags |= (1 << 6);
-    }
-}
-
 void uc32_translate_init(void);
 void switch_mode(CPUUniCore32State *, int);
 
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
index f99feaa..2b47d13 100644
--- a/target-xtensa/cpu.c
+++ b/target-xtensa/cpu.c
@@ -40,6 +40,39 @@  static void xtensa_cpu_set_pc(CPUState *cs, vaddr value)
     cpu->env.pc = value;
 }
 
+static void xtensa_cpu_get_tb_cpu_state(const CPUState *cs, vaddr *pc,
+                                        vaddr *cs_base, int *flags)
+{
+    XtensaCPU *cpu = XTENSA_CPU(cs);
+    CPUXtensaState *env = &cpu->env;
+
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = 0;
+    *flags |= xtensa_get_ring(env);
+    if (env->sregs[PS] & PS_EXCM) {
+        *flags |= XTENSA_TBFLAG_EXCM;
+    }
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) &&
+            (env->sregs[LITBASE] & 1)) {
+        *flags |= XTENSA_TBFLAG_LITBASE;
+    }
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_DEBUG)) {
+        if (xtensa_get_cintlevel(env) < env->config->debug_level) {
+            *flags |= XTENSA_TBFLAG_DEBUG;
+        }
+        if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) {
+            *flags |= XTENSA_TBFLAG_ICOUNT;
+        }
+    }
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_COPROCESSOR)) {
+        *flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT;
+    }
+    if (cs->singlestep_enabled && env->exception_taken) {
+        *flags |= XTENSA_TBFLAG_EXCEPTION;
+    }
+}
+
 static int xtensa_cpu_mmu_index(const CPUState *cs)
 {
     XtensaCPU *cpu = XTENSA_CPU(cs);
@@ -151,6 +184,7 @@  static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
     cc->dump_state = xtensa_cpu_dump_state;
     cc->mmu_index = xtensa_cpu_mmu_index;
     cc->set_pc = xtensa_cpu_set_pc;
+    cc->get_tb_cpu_state = xtensa_cpu_get_tb_cpu_state;
     cc->gdb_read_register = xtensa_cpu_gdb_read_register;
     cc->gdb_write_register = xtensa_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 4fdaf20..5d2a059 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -481,36 +481,6 @@  static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env,
 #define XTENSA_TBFLAG_CPENABLE_SHIFT 6
 #define XTENSA_TBFLAG_EXCEPTION 0x4000
 
-static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
-        target_ulong *cs_base, int *flags)
-{
-    *pc = env->pc;
-    *cs_base = 0;
-    *flags = 0;
-    *flags |= xtensa_get_ring(env);
-    if (env->sregs[PS] & PS_EXCM) {
-        *flags |= XTENSA_TBFLAG_EXCM;
-    }
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) &&
-            (env->sregs[LITBASE] & 1)) {
-        *flags |= XTENSA_TBFLAG_LITBASE;
-    }
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_DEBUG)) {
-        if (xtensa_get_cintlevel(env) < env->config->debug_level) {
-            *flags |= XTENSA_TBFLAG_DEBUG;
-        }
-        if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) {
-            *flags |= XTENSA_TBFLAG_ICOUNT;
-        }
-    }
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_COPROCESSOR)) {
-        *flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT;
-    }
-    if (ENV_GET_CPU(env)->singlestep_enabled && env->exception_taken) {
-        *flags |= XTENSA_TBFLAG_EXCEPTION;
-    }
-}
-
 #include "exec/cpu-all.h"
 #include "exec/exec-all.h"
 
diff --git a/translate-all.c b/translate-all.c
index 2c923c6..6000d4a 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -1011,11 +1011,12 @@  void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
     PageDesc *p;
     int n;
 #ifdef TARGET_HAS_PRECISE_SMC
+    CPUClass *cc = NULL;
     int current_tb_not_found = is_cpu_write_access;
     TranslationBlock *current_tb = NULL;
     int current_tb_modified = 0;
-    target_ulong current_pc = 0;
-    target_ulong current_cs_base = 0;
+    vaddr current_pc = 0;
+    vaddr current_cs_base = 0;
     int current_flags = 0;
 #endif /* TARGET_HAS_PRECISE_SMC */
 
@@ -1032,6 +1033,9 @@  void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
 #if defined(TARGET_HAS_PRECISE_SMC) || !defined(CONFIG_USER_ONLY)
     if (cpu != NULL) {
         env = cpu->env_ptr;
+#ifdef TARGET_HAS_PRECISE_SMC
+        cc = CPU_GET_CLASS(cpu);
+#endif
     }
 #endif
 
@@ -1073,7 +1077,7 @@  void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
 
                 current_tb_modified = 1;
                 cpu_restore_state_from_tb(current_tb, env, env->mem_io_pc);
-                cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
+                cc->get_tb_cpu_state(cpu, &current_pc, &current_cs_base,
                                      &current_flags);
             }
 #endif /* TARGET_HAS_PRECISE_SMC */
@@ -1157,10 +1161,11 @@  static void tb_invalidate_phys_page(tb_page_addr_t addr,
 #ifdef TARGET_HAS_PRECISE_SMC
     TranslationBlock *current_tb = NULL;
     CPUState *cpu = current_cpu;
+    CPUClass *cc = NULL;
     CPUArchState *env = NULL;
     int current_tb_modified = 0;
-    target_ulong current_pc = 0;
-    target_ulong current_cs_base = 0;
+    vaddr current_pc = 0;
+    vaddr current_cs_base = 0;
     int current_flags = 0;
 #endif
 
@@ -1176,6 +1181,7 @@  static void tb_invalidate_phys_page(tb_page_addr_t addr,
     }
     if (cpu != NULL) {
         env = cpu->env_ptr;
+        cc = CPU_GET_CLASS(cpu);
     }
 #endif
     while (tb != NULL) {
@@ -1192,7 +1198,7 @@  static void tb_invalidate_phys_page(tb_page_addr_t addr,
 
             current_tb_modified = 1;
             cpu_restore_state_from_tb(current_tb, env, pc);
-            cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
+            cc->get_tb_cpu_state(cpu, &current_pc, &current_cs_base,
                                  &current_flags);
         }
 #endif /* TARGET_HAS_PRECISE_SMC */