More efficient target register / TC accesses.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4794 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/cpu-exec.c b/cpu-exec.c
index b8c208b..9d00cff 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -197,7 +197,7 @@
 #elif defined(TARGET_MIPS)
     flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
     cs_base = 0;
-    pc = env->PC[env->current_tc];
+    pc = env->active_tc.PC;
 #elif defined(TARGET_M68K)
     flags = (env->fpcr & M68K_FPCR_PREC)  /* Bit  6 */
             | (env->sr & SR_S)            /* Bit  13 */
diff --git a/gdbstub.c b/gdbstub.c
index d4ca6f3..3f062be 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -704,17 +704,17 @@
     ptr = mem_buf;
     for (i = 0; i < 32; i++)
       {
-        *(target_ulong *)ptr = tswapl(env->gpr[env->current_tc][i]);
+        *(target_ulong *)ptr = tswapl(env->active_tc.gpr[i]);
         ptr += sizeof(target_ulong);
       }
 
     *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_Status);
     ptr += sizeof(target_ulong);
 
-    *(target_ulong *)ptr = tswapl(env->LO[env->current_tc][0]);
+    *(target_ulong *)ptr = tswapl(env->active_tc.LO[0]);
     ptr += sizeof(target_ulong);
 
-    *(target_ulong *)ptr = tswapl(env->HI[env->current_tc][0]);
+    *(target_ulong *)ptr = tswapl(env->active_tc.HI[0]);
     ptr += sizeof(target_ulong);
 
     *(target_ulong *)ptr = tswapl(env->CP0_BadVAddr);
@@ -723,7 +723,7 @@
     *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_Cause);
     ptr += sizeof(target_ulong);
 
-    *(target_ulong *)ptr = tswapl(env->PC[env->current_tc]);
+    *(target_ulong *)ptr = tswapl(env->active_tc.PC);
     ptr += sizeof(target_ulong);
 
     if (env->CP0_Config1 & (1 << CP0C1_FP))
@@ -781,17 +781,17 @@
     ptr = mem_buf;
     for (i = 0; i < 32; i++)
       {
-        env->gpr[env->current_tc][i] = tswapl(*(target_ulong *)ptr);
+        env->active_tc.gpr[i] = tswapl(*(target_ulong *)ptr);
         ptr += sizeof(target_ulong);
       }
 
     env->CP0_Status = tswapl(*(target_ulong *)ptr);
     ptr += sizeof(target_ulong);
 
-    env->LO[env->current_tc][0] = tswapl(*(target_ulong *)ptr);
+    env->active_tc.LO[0] = tswapl(*(target_ulong *)ptr);
     ptr += sizeof(target_ulong);
 
-    env->HI[env->current_tc][0] = tswapl(*(target_ulong *)ptr);
+    env->active_tc.HI[0] = tswapl(*(target_ulong *)ptr);
     ptr += sizeof(target_ulong);
 
     env->CP0_BadVAddr = tswapl(*(target_ulong *)ptr);
@@ -800,7 +800,7 @@
     env->CP0_Cause = tswapl(*(target_ulong *)ptr);
     ptr += sizeof(target_ulong);
 
-    env->PC[env->current_tc] = tswapl(*(target_ulong *)ptr);
+    env->active_tc.PC = tswapl(*(target_ulong *)ptr);
     ptr += sizeof(target_ulong);
 
     if (env->CP0_Config1 & (1 << CP0C1_FP))
@@ -1003,7 +1003,7 @@
 #elif defined (TARGET_SH4)
             env->pc = addr;
 #elif defined (TARGET_MIPS)
-            env->PC[env->current_tc] = addr;
+            env->active_tc.PC = addr;
 #elif defined (TARGET_CRIS)
             env->pc = addr;
 #endif
@@ -1040,7 +1040,7 @@
 #elif defined (TARGET_SH4)
             env->pc = addr;
 #elif defined (TARGET_MIPS)
-            env->PC[env->current_tc] = addr;
+            env->active_tc.PC = addr;
 #elif defined (TARGET_CRIS)
             env->pc = addr;
 #endif
diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index e29d8af..af09d95 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -65,7 +65,7 @@
     if (kernel_size >= 0) {
         if ((entry & ~0x7fffffffULL) == 0x80000000)
             entry = (int32_t)entry;
-        env->PC[env->current_tc] = entry;
+        env->active_tc.PC = entry;
     } else {
         fprintf(stderr, "qemu: could not load kernel '%s'\n",
                 loaderparams.kernel_filename);
@@ -152,7 +152,7 @@
         cpu_register_physical_memory(0x1fc00000LL,
                                      bios_size, bios_offset | IO_MEM_ROM);
         /* We have a boot vector start address. */
-        env->PC[env->current_tc] = (target_long)(int32_t)0xbfc00000;
+        env->active_tc.PC = (target_long)(int32_t)0xbfc00000;
     }
 
     if (kernel_filename) {
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 66ae135..4540cbf 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -87,7 +87,7 @@
     if (kernel_size >= 0) {
         if ((entry & ~0x7fffffffULL) == 0x80000000)
             entry = (int32_t)entry;
-        env->PC[env->current_tc] = entry;
+        env->active_tc.PC = entry;
     } else {
         fprintf(stderr, "qemu: could not load kernel '%s'\n",
                 loaderparams.kernel_filename);
diff --git a/linux-user/main.c b/linux-user/main.c
index a4ffea3..060ef82 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1779,8 +1779,8 @@
         trapnr = cpu_mips_exec(env);
         switch(trapnr) {
         case EXCP_SYSCALL:
-            syscall_num = env->gpr[env->current_tc][2] - 4000;
-            env->PC[env->current_tc] += 4;
+            syscall_num = env->active_tc.gpr[2] - 4000;
+            env->active_tc.PC += 4;
             if (syscall_num >= sizeof(mips_syscall_args)) {
                 ret = -ENOSYS;
             } else {
@@ -1789,7 +1789,7 @@
                 abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
 
                 nb_args = mips_syscall_args[syscall_num];
-                sp_reg = env->gpr[env->current_tc][29];
+                sp_reg = env->active_tc.gpr[29];
                 switch (nb_args) {
                 /* these arguments are taken from the stack */
                 /* FIXME - what to do if get_user() fails? */
@@ -1800,20 +1800,20 @@
                 default:
                     break;
                 }
-                ret = do_syscall(env, env->gpr[env->current_tc][2],
-                                 env->gpr[env->current_tc][4],
-                                 env->gpr[env->current_tc][5],
-                                 env->gpr[env->current_tc][6],
-                                 env->gpr[env->current_tc][7],
+                ret = do_syscall(env, env->active_tc.gpr[2],
+                                 env->active_tc.gpr[4],
+                                 env->active_tc.gpr[5],
+                                 env->active_tc.gpr[6],
+                                 env->active_tc.gpr[7],
                                  arg5, arg6/*, arg7, arg8*/);
             }
             if ((unsigned int)ret >= (unsigned int)(-1133)) {
-                env->gpr[env->current_tc][7] = 1; /* error flag */
+                env->active_tc.gpr[7] = 1; /* error flag */
                 ret = -ret;
             } else {
-                env->gpr[env->current_tc][7] = 0; /* error flag */
+                env->active_tc.gpr[7] = 0; /* error flag */
             }
-            env->gpr[env->current_tc][2] = ret;
+            env->active_tc.gpr[2] = ret;
             break;
         case EXCP_TLBL:
         case EXCP_TLBS:
@@ -2566,9 +2566,9 @@
         int i;
 
         for(i = 0; i < 32; i++) {
-            env->gpr[env->current_tc][i] = regs->regs[i];
+            env->active_tc.gpr[i] = regs->regs[i];
         }
-        env->PC[env->current_tc] = regs->cp0_epc;
+        env->active_tc.PC = regs->cp0_epc;
     }
 #elif defined(TARGET_SH4)
     {
diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h
index f3ef38d..6e1dc8b 100644
--- a/linux-user/mips/target_signal.h
+++ b/linux-user/mips/target_signal.h
@@ -23,7 +23,7 @@
 
 static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
 {
-    return state->gpr[state->current_tc][29];
+    return state->active_tc.gpr[29];
 }
 
 #endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/mips64/target_signal.h b/linux-user/mips64/target_signal.h
index f3ef38d..6e1dc8b 100644
--- a/linux-user/mips64/target_signal.h
+++ b/linux-user/mips64/target_signal.h
@@ -23,7 +23,7 @@
 
 static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
 {
-    return state->gpr[state->current_tc][29];
+    return state->active_tc.gpr[29];
 }
 
 #endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/mipsn32/target_signal.h b/linux-user/mipsn32/target_signal.h
index 5da8411..ff20d9e 100644
--- a/linux-user/mipsn32/target_signal.h
+++ b/linux-user/mipsn32/target_signal.h
@@ -23,7 +23,7 @@
 
 static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state)
 {
-    return state->gpr[state->current_tc][29];
+    return state->active_tc.gpr[29];
 }
 
 #endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 623a5e3..599b8af 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -2290,10 +2290,10 @@
 {
     int err = 0;
 
-    err |= __put_user(regs->PC[regs->current_tc], &sc->sc_pc);
+    err |= __put_user(regs->active_tc.PC, &sc->sc_pc);
 
-#define save_gp_reg(i) do {   							\
-        err |= __put_user(regs->gpr[regs->current_tc][i], &sc->sc_regs[i]);	\
+#define save_gp_reg(i) do {   						\
+        err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);	\
     } while(0)
     __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
     save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
@@ -2306,8 +2306,8 @@
     save_gp_reg(31);
 #undef save_gp_reg
 
-    err |= __put_user(regs->HI[regs->current_tc][0], &sc->sc_mdhi);
-    err |= __put_user(regs->LO[regs->current_tc][0], &sc->sc_mdlo);
+    err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
+    err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
 
     /* Not used yet, but might be useful if we ever have DSP suppport */
 #if 0
@@ -2367,11 +2367,11 @@
 
     err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
 
-    err |= __get_user(regs->HI[regs->current_tc][0], &sc->sc_mdhi);
-    err |= __get_user(regs->LO[regs->current_tc][0], &sc->sc_mdlo);
+    err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
+    err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
 
 #define restore_gp_reg(i) do {   							\
-        err |= __get_user(regs->gpr[regs->current_tc][i], &sc->sc_regs[i]);		\
+        err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);		\
     } while(0)
     restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
     restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
@@ -2437,7 +2437,7 @@
     unsigned long sp;
 
     /* Default to using normal stack */
-    sp = regs->gpr[regs->current_tc][29];
+    sp = regs->active_tc.gpr[29];
 
     /*
      * FPU emulator may have it's own trampoline active just
@@ -2486,15 +2486,15 @@
     * $25 and PC point to the signal handler, $29 points to the
     * struct sigframe.
     */
-    regs->gpr[regs->current_tc][ 4] = sig;
-    regs->gpr[regs->current_tc][ 5] = 0;
-    regs->gpr[regs->current_tc][ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
-    regs->gpr[regs->current_tc][29] = frame_addr;
-    regs->gpr[regs->current_tc][31] = frame_addr + offsetof(struct sigframe, sf_code);
+    regs->active_tc.gpr[ 4] = sig;
+    regs->active_tc.gpr[ 5] = 0;
+    regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
+    regs->active_tc.gpr[29] = frame_addr;
+    regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
     /* The original kernel code sets CP0_EPC to the handler
     * since it returns to userland using eret
     * we cannot do this here, and we must set PC directly */
-    regs->PC[regs->current_tc] = regs->gpr[regs->current_tc][25] = ka->_sa_handler;
+    regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
     unlock_user_struct(frame, frame_addr, 1);
     return;
 
@@ -2515,7 +2515,7 @@
 #if defined(DEBUG_SIGNAL)
     fprintf(stderr, "do_sigreturn\n");
 #endif
-    frame_addr = regs->gpr[regs->current_tc][29];
+    frame_addr = regs->active_tc.gpr[29];
     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
    	goto badframe;
 
@@ -2542,7 +2542,7 @@
     /* Unreached */
 #endif
 
-    regs->PC[regs->current_tc] = regs->CP0_EPC;
+    regs->active_tc.PC = regs->CP0_EPC;
     /* I am not sure this is right, but it seems to work
     * maybe a problem with nested signals ? */
     regs->CP0_EPC = 0;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index cd90946..839ac7f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -3686,7 +3686,7 @@
             if (!is_error(ret)) {
 #if defined(TARGET_MIPS)
                 CPUMIPSState *env = (CPUMIPSState*)cpu_env;
-		env->gpr[env->current_tc][3] = host_pipe[1];
+		env->active_tc.gpr[3] = host_pipe[1];
 		ret = host_pipe[0];
 #elif defined(TARGET_SH4)
 		((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
diff --git a/monitor.c b/monitor.c
index 914f4c6..fc135ca 100644
--- a/monitor.c
+++ b/monitor.c
@@ -316,7 +316,7 @@
 #elif defined(TARGET_SPARC)
         term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc);
 #elif defined(TARGET_MIPS)
-        term_printf(" PC=0x" TARGET_FMT_lx, env->PC[env->current_tc]);
+        term_printf(" PC=0x" TARGET_FMT_lx, env->active_tc.PC);
 #endif
         if (env->halted)
             term_printf(" (halted)");
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index fdb05cc..78851ed 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -134,29 +134,53 @@
 #define MIPS_TC_MAX 5
 #define MIPS_DSP_ACC 4
 
+typedef struct TCState TCState;
+struct TCState {
+    target_ulong gpr[32];
+    target_ulong PC;
+    target_ulong HI[MIPS_DSP_ACC];
+    target_ulong LO[MIPS_DSP_ACC];
+    target_ulong ACX[MIPS_DSP_ACC];
+    target_ulong DSPControl;
+    int32_t CP0_TCStatus;
+#define CP0TCSt_TCU3	31
+#define CP0TCSt_TCU2	30
+#define CP0TCSt_TCU1	29
+#define CP0TCSt_TCU0	28
+#define CP0TCSt_TMX	27
+#define CP0TCSt_RNST	23
+#define CP0TCSt_TDS	21
+#define CP0TCSt_DT	20
+#define CP0TCSt_DA	15
+#define CP0TCSt_A	13
+#define CP0TCSt_TKSU	11
+#define CP0TCSt_IXMT	10
+#define CP0TCSt_TASID	0
+    int32_t CP0_TCBind;
+#define CP0TCBd_CurTC	21
+#define CP0TCBd_TBE	17
+#define CP0TCBd_CurVPE	0
+    target_ulong CP0_TCHalt;
+    target_ulong CP0_TCContext;
+    target_ulong CP0_TCSchedule;
+    target_ulong CP0_TCScheFBack;
+    int32_t CP0_Debug_tcstatus;
+};
+
 typedef struct CPUMIPSState CPUMIPSState;
 struct CPUMIPSState {
-    /* General integer registers */
-    target_ulong gpr[MIPS_SHADOW_SET_MAX][32];
-    /* Special registers */
-    target_ulong PC[MIPS_TC_MAX];
+    TCState active_tc;
+
     /* temporary hack for FP globals */
 #ifndef USE_HOST_FLOAT_REGS
     fpr_t ft0;
     fpr_t ft1;
     fpr_t ft2;
 #endif
-    target_ulong HI[MIPS_TC_MAX][MIPS_DSP_ACC];
-    target_ulong LO[MIPS_TC_MAX][MIPS_DSP_ACC];
-    target_ulong ACX[MIPS_TC_MAX][MIPS_DSP_ACC];
-    target_ulong DSPControl[MIPS_TC_MAX];
-
     CPUMIPSMVPContext *mvp;
     CPUMIPSTLBContext *tlb;
     CPUMIPSFPUContext *fpu;
     uint32_t current_tc;
-    target_ulong *current_tc_gprs;
-    target_ulong *current_tc_hi;
 
     uint32_t SEGBITS;
     target_ulong SEGMask;
@@ -206,28 +230,6 @@
 #define CP0VPEOpt_DWX1	1
 #define CP0VPEOpt_DWX0	0
     target_ulong CP0_EntryLo0;
-    int32_t CP0_TCStatus[MIPS_TC_MAX];
-#define CP0TCSt_TCU3	31
-#define CP0TCSt_TCU2	30
-#define CP0TCSt_TCU1	29
-#define CP0TCSt_TCU0	28
-#define CP0TCSt_TMX	27
-#define CP0TCSt_RNST	23
-#define CP0TCSt_TDS	21
-#define CP0TCSt_DT	20
-#define CP0TCSt_DA	15
-#define CP0TCSt_A	13
-#define CP0TCSt_TKSU	11
-#define CP0TCSt_IXMT	10
-#define CP0TCSt_TASID	0
-    int32_t CP0_TCBind[MIPS_TC_MAX];
-#define CP0TCBd_CurTC	21
-#define CP0TCBd_TBE	17
-#define CP0TCBd_CurVPE	0
-    target_ulong CP0_TCHalt[MIPS_TC_MAX];
-    target_ulong CP0_TCContext[MIPS_TC_MAX];
-    target_ulong CP0_TCSchedule[MIPS_TC_MAX];
-    target_ulong CP0_TCScheFBack[MIPS_TC_MAX];
     target_ulong CP0_EntryLo1;
     target_ulong CP0_Context;
     int32_t CP0_PageMask;
@@ -398,7 +400,6 @@
 #define CP0DB_DDBL 2
 #define CP0DB_DBp  1
 #define CP0DB_DSS  0
-    int32_t CP0_Debug_tcstatus[MIPS_TC_MAX];
     target_ulong CP0_DEPC;
     int32_t CP0_Performance0;
     int32_t CP0_TagLo;
@@ -407,6 +408,8 @@
     int32_t CP0_DataHi;
     target_ulong CP0_ErrorEPC;
     int32_t CP0_DESAVE;
+    /* We waste some space so we can handle shadow registers like TCs. */
+    TCState tcs[MIPS_SHADOW_SET_MAX];
     /* Qemu */
     int interrupt_request;
     int error_code;
@@ -501,9 +504,9 @@
 static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 {
     if (newsp)
-        env->gpr[env->current_tc][29] = newsp;
-    env->gpr[env->current_tc][7] = 0;
-    env->gpr[env->current_tc][2] = 0;
+        env->active_tc.gpr[29] = newsp;
+    env->active_tc.gpr[7] = 0;
+    env->active_tc.gpr[2] = 0;
 }
 #endif
 
diff --git a/target-mips/helper.c b/target-mips/helper.c
index b962295..11f58c2 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -241,7 +241,7 @@
         cpu_dump_state(env, logfile, fprintf, 0);
 #endif
         fprintf(logfile, "%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n",
-                __func__, env->PC[env->current_tc], address, rw, mmu_idx, is_softmmu);
+                __func__, env->active_tc.PC, address, rw, mmu_idx, is_softmmu);
     }
 
     rw &= 1;
@@ -370,7 +370,7 @@
             name = excp_names[env->exception_index];
 
         fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
-                __func__, env->PC[env->current_tc], env->CP0_EPC, name);
+                __func__, env->active_tc.PC, env->CP0_EPC, name);
     }
     if (env->exception_index == EXCP_EXT_INTERRUPT &&
         (env->hflags & MIPS_HFLAG_DM))
@@ -384,7 +384,7 @@
          * (but we assume the pc has always been updated during
          *  code translation).
          */
-        env->CP0_DEPC = env->PC[env->current_tc];
+        env->CP0_DEPC = env->active_tc.PC;
         goto enter_debug_mode;
     case EXCP_DINT:
         env->CP0_Debug |= 1 << CP0DB_DINT;
@@ -404,10 +404,10 @@
         if (env->hflags & MIPS_HFLAG_BMASK) {
             /* If the exception was raised from a delay slot,
                come back to the jump.  */
-            env->CP0_DEPC = env->PC[env->current_tc] - 4;
+            env->CP0_DEPC = env->active_tc.PC - 4;
             env->hflags &= ~MIPS_HFLAG_BMASK;
         } else {
-            env->CP0_DEPC = env->PC[env->current_tc];
+            env->CP0_DEPC = env->active_tc.PC;
         }
     enter_debug_mode:
         env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
@@ -415,7 +415,7 @@
         /* EJTAG probe trap enable is not implemented... */
         if (!(env->CP0_Status & (1 << CP0St_EXL)))
             env->CP0_Cause &= ~(1 << CP0Ca_BD);
-        env->PC[env->current_tc] = (int32_t)0xBFC00480;
+        env->active_tc.PC = (int32_t)0xBFC00480;
         break;
     case EXCP_RESET:
         cpu_reset(env);
@@ -430,17 +430,17 @@
         if (env->hflags & MIPS_HFLAG_BMASK) {
             /* If the exception was raised from a delay slot,
                come back to the jump.  */
-            env->CP0_ErrorEPC = env->PC[env->current_tc] - 4;
+            env->CP0_ErrorEPC = env->active_tc.PC - 4;
             env->hflags &= ~MIPS_HFLAG_BMASK;
         } else {
-            env->CP0_ErrorEPC = env->PC[env->current_tc];
+            env->CP0_ErrorEPC = env->active_tc.PC;
         }
         env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
         env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
         env->hflags &= ~(MIPS_HFLAG_KSU);
         if (!(env->CP0_Status & (1 << CP0St_EXL)))
             env->CP0_Cause &= ~(1 << CP0Ca_BD);
-        env->PC[env->current_tc] = (int32_t)0xBFC00000;
+        env->active_tc.PC = (int32_t)0xBFC00000;
         break;
     case EXCP_EXT_INTERRUPT:
         cause = 0;
@@ -545,10 +545,10 @@
             if (env->hflags & MIPS_HFLAG_BMASK) {
                 /* If the exception was raised from a delay slot,
                    come back to the jump.  */
-                env->CP0_EPC = env->PC[env->current_tc] - 4;
+                env->CP0_EPC = env->active_tc.PC - 4;
                 env->CP0_Cause |= (1 << CP0Ca_BD);
             } else {
-                env->CP0_EPC = env->PC[env->current_tc];
+                env->CP0_EPC = env->active_tc.PC;
                 env->CP0_Cause &= ~(1 << CP0Ca_BD);
             }
             env->CP0_Status |= (1 << CP0St_EXL);
@@ -557,11 +557,11 @@
         }
         env->hflags &= ~MIPS_HFLAG_BMASK;
         if (env->CP0_Status & (1 << CP0St_BEV)) {
-            env->PC[env->current_tc] = (int32_t)0xBFC00200;
+            env->active_tc.PC = (int32_t)0xBFC00200;
         } else {
-            env->PC[env->current_tc] = (int32_t)(env->CP0_EBase & ~0x3ff);
+            env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
         }
-        env->PC[env->current_tc] += offset;
+        env->active_tc.PC += offset;
         env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
         break;
     default:
@@ -575,7 +575,7 @@
     if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
         fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
                 "    S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
-                __func__, env->PC[env->current_tc], env->CP0_EPC, cause,
+                __func__, env->active_tc.PC, env->CP0_EPC, cause,
                 env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
                 env->CP0_DEPC);
     }
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index eae5b74..fe3bbd4 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -89,25 +89,25 @@
 /* 64 bits arithmetic for 32 bits hosts */
 static always_inline uint64_t get_HILO (void)
 {
-    return ((uint64_t)(env->HI[env->current_tc][0]) << 32) | (uint32_t)env->LO[env->current_tc][0];
+    return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
 }
 
 static always_inline void set_HILO (uint64_t HILO)
 {
-    env->LO[env->current_tc][0] = (int32_t)HILO;
-    env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
+    env->active_tc.LO[0] = (int32_t)HILO;
+    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
 }
 
 static always_inline void set_HIT0_LO (target_ulong t0, uint64_t HILO)
 {
-    env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
-    t0 = env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
+    env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
+    t0 = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
 }
 
 static always_inline void set_HI_LOT0 (target_ulong t0, uint64_t HILO)
 {
-    t0 = env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
-    env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
+    t0 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
+    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
 }
 
 #if TARGET_LONG_BITS > HOST_LONG_BITS
@@ -246,12 +246,12 @@
 #ifdef TARGET_MIPS64
 void do_dmult (target_ulong t0, target_ulong t1)
 {
-    muls64(&(env->LO[env->current_tc][0]), &(env->HI[env->current_tc][0]), t0, t1);
+    muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), t0, t1);
 }
 
 void do_dmultu (target_ulong t0, target_ulong t1)
 {
-    mulu64(&(env->LO[env->current_tc][0]), &(env->HI[env->current_tc][0]), t0, t1);
+    mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), t0, t1);
 }
 #endif
 
@@ -672,86 +672,107 @@
 
 target_ulong do_mfc0_tcstatus (void)
 {
-    return env->CP0_TCStatus[env->current_tc];
+    return env->active_tc.CP0_TCStatus;
 }
 
 target_ulong do_mftc0_tcstatus(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    return env->CP0_TCStatus[other_tc];
+    if (other_tc == env->current_tc)
+        return env->active_tc.CP0_TCStatus;
+    else
+        return env->tcs[other_tc].CP0_TCStatus;
 }
 
 target_ulong do_mfc0_tcbind (void)
 {
-    return env->CP0_TCBind[env->current_tc];
+    return env->active_tc.CP0_TCBind;
 }
 
 target_ulong do_mftc0_tcbind(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    return env->CP0_TCBind[other_tc];
+    if (other_tc == env->current_tc)
+        return env->active_tc.CP0_TCBind;
+    else
+        return env->tcs[other_tc].CP0_TCBind;
 }
 
 target_ulong do_mfc0_tcrestart (void)
 {
-    return env->PC[env->current_tc];
+    return env->active_tc.PC;
 }
 
 target_ulong do_mftc0_tcrestart(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    return env->PC[other_tc];
+    if (other_tc == env->current_tc)
+        return env->active_tc.PC;
+    else
+        return env->tcs[other_tc].PC;
 }
 
 target_ulong do_mfc0_tchalt (void)
 {
-    return env->CP0_TCHalt[env->current_tc];
+    return env->active_tc.CP0_TCHalt;
 }
 
 target_ulong do_mftc0_tchalt(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    return env->CP0_TCHalt[other_tc];
+    if (other_tc == env->current_tc)
+        return env->active_tc.CP0_TCHalt;
+    else
+        return env->tcs[other_tc].CP0_TCHalt;
 }
 
 target_ulong do_mfc0_tccontext (void)
 {
-    return env->CP0_TCContext[env->current_tc];
+    return env->active_tc.CP0_TCContext;
 }
 
 target_ulong do_mftc0_tccontext(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    return env->CP0_TCContext[other_tc];
+    if (other_tc == env->current_tc)
+        return env->active_tc.CP0_TCContext;
+    else
+        return env->tcs[other_tc].CP0_TCContext;
 }
 
 target_ulong do_mfc0_tcschedule (void)
 {
-    return env->CP0_TCSchedule[env->current_tc];
+    return env->active_tc.CP0_TCSchedule;
 }
 
 target_ulong do_mftc0_tcschedule(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    return env->CP0_TCSchedule[other_tc];
+    if (other_tc == env->current_tc)
+        return env->active_tc.CP0_TCSchedule;
+    else
+        return env->tcs[other_tc].CP0_TCSchedule;
 }
 
 target_ulong do_mfc0_tcschefback (void)
 {
-    return env->CP0_TCScheFBack[env->current_tc];
+    return env->active_tc.CP0_TCScheFBack;
 }
 
 target_ulong do_mftc0_tcschefback(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    return env->CP0_TCScheFBack[other_tc];
+    if (other_tc == env->current_tc)
+        return env->active_tc.CP0_TCScheFBack;
+    else
+        return env->tcs[other_tc].CP0_TCScheFBack;
 }
 
 target_ulong do_mfc0_count (void)
@@ -762,15 +783,26 @@
 target_ulong do_mftc0_entryhi(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    int32_t tcstatus;
 
-    return (env->CP0_EntryHi & ~0xff) | (env->CP0_TCStatus[other_tc] & 0xff);
+    if (other_tc == env->current_tc)
+        tcstatus = env->active_tc.CP0_TCStatus;
+    else
+        tcstatus = env->tcs[other_tc].CP0_TCStatus;
+
+    return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff);
 }
 
 target_ulong do_mftc0_status(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
-    uint32_t tcstatus = env->CP0_TCStatus[other_tc];
     target_ulong t0;
+    int32_t tcstatus;
+
+    if (other_tc == env->current_tc)
+        tcstatus = env->active_tc.CP0_TCStatus;
+    else
+        tcstatus = env->tcs[other_tc].CP0_TCStatus;
 
     t0 = env->CP0_Status & ~0xf1000018;
     t0 |= tcstatus & (0xf << CP0TCSt_TCU0);
@@ -807,37 +839,42 @@
 target_ulong do_mftc0_debug(void)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    int32_t tcstatus;
+
+    if (other_tc == env->current_tc)
+        tcstatus = env->active_tc.CP0_Debug_tcstatus;
+    else
+        tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus;
 
     /* XXX: Might be wrong, check with EJTAG spec. */
     return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
-            (env->CP0_Debug_tcstatus[other_tc] &
-             ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
+            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
 }
 
 #if defined(TARGET_MIPS64)
 target_ulong do_dmfc0_tcrestart (void)
 {
-    return env->PC[env->current_tc];
+    return env->active_tc.PC;
 }
 
 target_ulong do_dmfc0_tchalt (void)
 {
-    return env->CP0_TCHalt[env->current_tc];
+    return env->active_tc.CP0_TCHalt;
 }
 
 target_ulong do_dmfc0_tccontext (void)
 {
-    return env->CP0_TCContext[env->current_tc];
+    return env->active_tc.CP0_TCContext;
 }
 
 target_ulong do_dmfc0_tcschedule (void)
 {
-    return env->CP0_TCSchedule[env->current_tc];
+    return env->active_tc.CP0_TCSchedule;
 }
 
 target_ulong do_dmfc0_tcschefback (void)
 {
-    return env->CP0_TCScheFBack[env->current_tc];
+    return env->active_tc.CP0_TCScheFBack;
 }
 
 target_ulong do_dmfc0_lladdr (void)
@@ -955,11 +992,11 @@
     uint32_t mask = env->CP0_TCStatus_rw_bitmask;
     uint32_t newval;
 
-    newval = (env->CP0_TCStatus[env->current_tc] & ~mask) | (t0 & mask);
+    newval = (env->active_tc.CP0_TCStatus & ~mask) | (t0 & mask);
 
     // TODO: Sync with CP0_Status.
 
-    env->CP0_TCStatus[env->current_tc] = newval;
+    env->active_tc.CP0_TCStatus = newval;
 }
 
 void do_mttc0_tcstatus (target_ulong t0)
@@ -968,7 +1005,10 @@
 
     // TODO: Sync with CP0_Status.
 
-    env->CP0_TCStatus[other_tc] = t0;
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_TCStatus = t0;
+    else
+        env->tcs[other_tc].CP0_TCStatus = t0;
 }
 
 void do_mtc0_tcbind (target_ulong t0)
@@ -978,8 +1018,8 @@
 
     if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
         mask |= (1 << CP0TCBd_CurVPE);
-    newval = (env->CP0_TCBind[env->current_tc] & ~mask) | (t0 & mask);
-    env->CP0_TCBind[env->current_tc] = newval;
+    newval = (env->active_tc.CP0_TCBind & ~mask) | (t0 & mask);
+    env->active_tc.CP0_TCBind = newval;
 }
 
 void do_mttc0_tcbind (target_ulong t0)
@@ -990,14 +1030,19 @@
 
     if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
         mask |= (1 << CP0TCBd_CurVPE);
-    newval = (env->CP0_TCBind[other_tc] & ~mask) | (t0 & mask);
-    env->CP0_TCBind[other_tc] = newval;
+    if (other_tc == env->current_tc) {
+        newval = (env->active_tc.CP0_TCBind & ~mask) | (t0 & mask);
+        env->active_tc.CP0_TCBind = newval;
+    } else {
+        newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (t0 & mask);
+        env->tcs[other_tc].CP0_TCBind = newval;
+    }
 }
 
 void do_mtc0_tcrestart (target_ulong t0)
 {
-    env->PC[env->current_tc] = t0;
-    env->CP0_TCStatus[env->current_tc] &= ~(1 << CP0TCSt_TDS);
+    env->active_tc.PC = t0;
+    env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
     env->CP0_LLAddr = 0ULL;
     /* MIPS16 not implemented. */
 }
@@ -1006,15 +1051,22 @@
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    env->PC[other_tc] = t0;
-    env->CP0_TCStatus[other_tc] &= ~(1 << CP0TCSt_TDS);
-    env->CP0_LLAddr = 0ULL;
-    /* MIPS16 not implemented. */
+    if (other_tc == env->current_tc) {
+        env->active_tc.PC = t0;
+        env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
+        env->CP0_LLAddr = 0ULL;
+        /* MIPS16 not implemented. */
+    } else {
+        env->tcs[other_tc].PC = t0;
+        env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
+        env->CP0_LLAddr = 0ULL;
+        /* MIPS16 not implemented. */
+    }
 }
 
 void do_mtc0_tchalt (target_ulong t0)
 {
-    env->CP0_TCHalt[env->current_tc] = t0 & 0x1;
+    env->active_tc.CP0_TCHalt = t0 & 0x1;
 
     // TODO: Halt TC / Restart (if allocated+active) TC.
 }
@@ -1025,43 +1077,55 @@
 
     // TODO: Halt TC / Restart (if allocated+active) TC.
 
-    env->CP0_TCHalt[other_tc] = t0;
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_TCHalt = t0;
+    else
+        env->tcs[other_tc].CP0_TCHalt = t0;
 }
 
 void do_mtc0_tccontext (target_ulong t0)
 {
-    env->CP0_TCContext[env->current_tc] = t0;
+    env->active_tc.CP0_TCContext = t0;
 }
 
 void do_mttc0_tccontext (target_ulong t0)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    env->CP0_TCContext[other_tc] = t0;
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_TCContext = t0;
+    else
+        env->tcs[other_tc].CP0_TCContext = t0;
 }
 
 void do_mtc0_tcschedule (target_ulong t0)
 {
-    env->CP0_TCSchedule[env->current_tc] = t0;
+    env->active_tc.CP0_TCSchedule = t0;
 }
 
 void do_mttc0_tcschedule (target_ulong t0)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    env->CP0_TCSchedule[other_tc] = t0;
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_TCSchedule = t0;
+    else
+        env->tcs[other_tc].CP0_TCSchedule = t0;
 }
 
 void do_mtc0_tcschefback (target_ulong t0)
 {
-    env->CP0_TCScheFBack[env->current_tc] = t0;
+    env->active_tc.CP0_TCScheFBack = t0;
 }
 
 void do_mttc0_tcschefback (target_ulong t0)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    env->CP0_TCScheFBack[other_tc] = t0;
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_TCScheFBack = t0;
+    else
+        env->tcs[other_tc].CP0_TCScheFBack = t0;
 }
 
 void do_mtc0_entrylo1 (target_ulong t0)
@@ -1142,8 +1206,8 @@
     old = env->CP0_EntryHi;
     env->CP0_EntryHi = val;
     if (env->CP0_Config3 & (1 << CP0C3_MT)) {
-        uint32_t tcst = env->CP0_TCStatus[env->current_tc] & ~0xff;
-        env->CP0_TCStatus[env->current_tc] = tcst | (val & 0xff);
+        uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff;
+        env->active_tc.CP0_TCStatus = tcst | (val & 0xff);
     }
     /* If the ASID changes, flush qemu's TLB.  */
     if ((old & 0xFF) != (val & 0xFF))
@@ -1153,9 +1217,16 @@
 void do_mttc0_entryhi(target_ulong t0)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    int32_t tcstatus;
 
     env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (t0 & ~0xff);
-    env->CP0_TCStatus[other_tc] = (env->CP0_TCStatus[other_tc] & ~0xff) | (t0 & 0xff);
+    if (other_tc == env->current_tc) {
+        tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (t0 & 0xff);
+        env->active_tc.CP0_TCStatus = tcstatus;
+    } else {
+        tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (t0 & 0xff);
+        env->tcs[other_tc].CP0_TCStatus = tcstatus;
+    }
 }
 
 void do_mtc0_compare (target_ulong t0)
@@ -1180,13 +1251,16 @@
 void do_mttc0_status(target_ulong t0)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
-    uint32_t tcstatus = env->CP0_TCStatus[other_tc];
+    int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus;
 
     env->CP0_Status = t0 & ~0xf1000018;
     tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (t0 & (0xf << CP0St_CU0));
     tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((t0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
     tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((t0 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU));
-    env->CP0_TCStatus[other_tc] = tcstatus;
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_TCStatus = tcstatus;
+    else
+        env->tcs[other_tc].CP0_TCStatus = tcstatus;
 }
 
 void do_mtc0_intctl (target_ulong t0)
@@ -1279,9 +1353,13 @@
 void do_mttc0_debug(target_ulong t0)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    uint32_t val = t0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
 
     /* XXX: Might be wrong, check with EJTAG spec. */
-    env->CP0_Debug_tcstatus[other_tc] = t0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
+    if (other_tc == env->current_tc)
+        env->active_tc.CP0_Debug_tcstatus = val;
+    else
+        env->tcs[other_tc].CP0_Debug_tcstatus = val;
     env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
                      (t0 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
 }
@@ -1336,70 +1414,100 @@
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    return env->gpr[other_tc][sel];
+    if (other_tc == env->current_tc)
+        return env->active_tc.gpr[sel];
+    else
+        return env->tcs[other_tc].gpr[sel];
 }
 
 target_ulong do_mftlo(target_ulong t0, uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    return env->LO[other_tc][sel];
+    if (other_tc == env->current_tc)
+        return env->active_tc.LO[sel];
+    else
+        return env->tcs[other_tc].LO[sel];
 }
 
 target_ulong do_mfthi(target_ulong t0, uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    return env->HI[other_tc][sel];
+    if (other_tc == env->current_tc)
+        return env->active_tc.HI[sel];
+    else
+        return env->tcs[other_tc].HI[sel];
 }
 
 target_ulong do_mftacx(target_ulong t0, uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    return env->ACX[other_tc][sel];
+    if (other_tc == env->current_tc)
+        return env->active_tc.ACX[sel];
+    else
+        return env->tcs[other_tc].ACX[sel];
 }
 
 target_ulong do_mftdsp(target_ulong t0)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    return env->DSPControl[other_tc];
+    if (other_tc == env->current_tc)
+        return env->active_tc.DSPControl;
+    else
+        return env->tcs[other_tc].DSPControl;
 }
 
 void do_mttgpr(target_ulong t0, uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    env->gpr[other_tc][sel] = t0;
+    if (other_tc == env->current_tc)
+        env->active_tc.gpr[sel] = t0;
+    else
+        env->tcs[other_tc].gpr[sel] = t0;
 }
 
 void do_mttlo(target_ulong t0, uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    env->LO[other_tc][sel] = t0;
+    if (other_tc == env->current_tc)
+        env->active_tc.LO[sel] = t0;
+    else
+        env->tcs[other_tc].LO[sel] = t0;
 }
 
 void do_mtthi(target_ulong t0, uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    env->HI[other_tc][sel] = t0;
+    if (other_tc == env->current_tc)
+        env->active_tc.HI[sel] = t0;
+    else
+        env->tcs[other_tc].HI[sel] = t0;
 }
 
 void do_mttacx(target_ulong t0, uint32_t sel)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    env->ACX[other_tc][sel] = t0;
+    if (other_tc == env->current_tc)
+        env->active_tc.ACX[sel] = t0;
+    else
+        env->tcs[other_tc].ACX[sel] = t0;
 }
 
 void do_mttdsp(target_ulong t0)
 {
     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    env->DSPControl[other_tc] = t0;
+    if (other_tc == env->current_tc)
+        env->active_tc.DSPControl = t0;
+    else
+        env->tcs[other_tc].DSPControl = t0;
 }
 
 /* MIPS MT functions */
@@ -1452,7 +1560,7 @@
         /* No scheduling policy implemented. */
         if (t0 != -2) {
             if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
-                env->CP0_TCStatus[env->current_tc] & (1 << CP0TCSt_DT)) {
+                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
                 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
                 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
                 do_raise_exception(EXCP_THREAD);
@@ -1659,7 +1767,7 @@
 void debug_pre_eret (void)
 {
     fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
-            env->PC[env->current_tc], env->CP0_EPC);
+            env->active_tc.PC, env->CP0_EPC);
     if (env->CP0_Status & (1 << CP0St_ERL))
         fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
     if (env->hflags & MIPS_HFLAG_DM)
@@ -1670,7 +1778,7 @@
 void debug_post_eret (void)
 {
     fprintf(logfile, "  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
-            env->PC[env->current_tc], env->CP0_EPC);
+            env->active_tc.PC, env->CP0_EPC);
     if (env->CP0_Status & (1 << CP0St_ERL))
         fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
     if (env->hflags & MIPS_HFLAG_DM)
@@ -1688,10 +1796,10 @@
     if (loglevel & CPU_LOG_EXEC)
         debug_pre_eret();
     if (env->CP0_Status & (1 << CP0St_ERL)) {
-        env->PC[env->current_tc] = env->CP0_ErrorEPC;
+        env->active_tc.PC = env->CP0_ErrorEPC;
         env->CP0_Status &= ~(1 << CP0St_ERL);
     } else {
-        env->PC[env->current_tc] = env->CP0_EPC;
+        env->active_tc.PC = env->CP0_EPC;
         env->CP0_Status &= ~(1 << CP0St_EXL);
     }
     compute_hflags(env);
@@ -1704,7 +1812,7 @@
 {
     if (loglevel & CPU_LOG_EXEC)
         debug_pre_eret();
-    env->PC[env->current_tc] = env->CP0_DEPC;
+    env->active_tc.PC = env->CP0_DEPC;
     env->hflags &= MIPS_HFLAG_DM;
     compute_hflags(env);
     if (loglevel & CPU_LOG_EXEC)
@@ -1804,21 +1912,21 @@
     function /= 2;
     switch (function) {
     case 2: /* TODO: char inbyte(int waitflag); */
-        if (env->gpr[env->current_tc][4] == 0)
-            env->gpr[env->current_tc][2] = -1;
+        if (env->active_tc.gpr[4] == 0)
+            env->active_tc.gpr[2] = -1;
         /* Fall through */
     case 11: /* TODO: char inbyte (void); */
-        env->gpr[env->current_tc][2] = -1;
+        env->active_tc.gpr[2] = -1;
         break;
     case 3:
     case 12:
-        printf("%c", (char)(env->gpr[env->current_tc][4] & 0xFF));
+        printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
         break;
     case 17:
         break;
     case 158:
         {
-            unsigned char *fmt = (void *)(unsigned long)env->gpr[env->current_tc][4];
+            unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
             printf("%s", fmt);
         }
         break;
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 41a27b4..c4d91f0 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -423,7 +423,7 @@
 };
 
 /* global register indices */
-static TCGv cpu_env, current_tc_gprs, current_tc_hi, current_fpu;
+static TCGv cpu_env, current_fpu;
 
 /* FPU TNs, global for now. */
 static TCGv fpu32_T[3], fpu64_T[3], fpu32h_T[3];
@@ -563,40 +563,40 @@
     if (reg == 0)
         tcg_gen_movi_tl(t, 0);
     else
-        tcg_gen_ld_tl(t, current_tc_gprs, sizeof(target_ulong) * reg);
+        tcg_gen_ld_tl(t, cpu_env, offsetof(CPUState, active_tc.gpr) +
+                                  sizeof(target_ulong) * reg);
 }
 
 static inline void gen_store_gpr (TCGv t, int reg)
 {
     if (reg != 0)
-        tcg_gen_st_tl(t, current_tc_gprs, sizeof(target_ulong) * reg);
+        tcg_gen_st_tl(t, cpu_env, offsetof(CPUState, active_tc.gpr) +
+                                  sizeof(target_ulong) * reg);
 }
 
 /* Moves to/from HI and LO registers.  */
 static inline void gen_load_LO (TCGv t, int reg)
 {
-    tcg_gen_ld_tl(t, current_tc_hi,
-                  offsetof(CPUState, LO)
-                  - offsetof(CPUState, HI)
-                  + sizeof(target_ulong) * reg);
+    tcg_gen_ld_tl(t, cpu_env, offsetof(CPUState, active_tc.LO) +
+                              sizeof(target_ulong) * reg);
 }
 
 static inline void gen_store_LO (TCGv t, int reg)
 {
-    tcg_gen_st_tl(t, current_tc_hi,
-                  offsetof(CPUState, LO)
-                  - offsetof(CPUState, HI)
-                  + sizeof(target_ulong) * reg);
+    tcg_gen_st_tl(t, cpu_env, offsetof(CPUState, active_tc.LO) +
+                              sizeof(target_ulong) * reg);
 }
 
 static inline void gen_load_HI (TCGv t, int reg)
 {
-    tcg_gen_ld_tl(t, current_tc_hi, sizeof(target_ulong) * reg);
+    tcg_gen_ld_tl(t, cpu_env, offsetof(CPUState, active_tc.HI) +
+                              sizeof(target_ulong) * reg);
 }
 
 static inline void gen_store_HI (TCGv t, int reg)
 {
-    tcg_gen_st_tl(t, current_tc_hi, sizeof(target_ulong) * reg);
+    tcg_gen_st_tl(t, cpu_env, offsetof(CPUState, active_tc.HI) +
+                              sizeof(target_ulong) * reg);
 }
 
 /* Moves to/from shadow registers. */
@@ -805,38 +805,18 @@
 static inline void gen_save_pc(target_ulong pc)
 {
     TCGv r_tmp = tcg_temp_new(TCG_TYPE_TL);
-    TCGv r_tc_off = tcg_temp_new(TCG_TYPE_I32);
-    TCGv r_tc_off_ptr = tcg_temp_new(TCG_TYPE_PTR);
-    TCGv r_ptr = tcg_temp_new(TCG_TYPE_PTR);
 
     tcg_gen_movi_tl(r_tmp, pc);
-    tcg_gen_ld_i32(r_tc_off, cpu_env, offsetof(CPUState, current_tc));
-    tcg_gen_muli_i32(r_tc_off, r_tc_off, sizeof(target_ulong));
-    tcg_gen_ext_i32_ptr(r_tc_off_ptr, r_tc_off);
-    tcg_gen_add_ptr(r_ptr, cpu_env, r_tc_off_ptr);
-    tcg_gen_st_tl(r_tmp, r_ptr, offsetof(CPUState, PC));
-    tcg_temp_free(r_tc_off);
-    tcg_temp_free(r_tc_off_ptr);
-    tcg_temp_free(r_ptr);
+    tcg_gen_st_tl(r_tmp, cpu_env, offsetof(CPUState, active_tc.PC));
     tcg_temp_free(r_tmp);
 }
 
 static inline void gen_breg_pc(void)
 {
     TCGv r_tmp = tcg_temp_new(TCG_TYPE_TL);
-    TCGv r_tc_off = tcg_temp_new(TCG_TYPE_I32);
-    TCGv r_tc_off_ptr = tcg_temp_new(TCG_TYPE_PTR);
-    TCGv r_ptr = tcg_temp_new(TCG_TYPE_PTR);
 
     tcg_gen_ld_tl(r_tmp, cpu_env, offsetof(CPUState, btarget));
-    tcg_gen_ld_i32(r_tc_off, cpu_env, offsetof(CPUState, current_tc));
-    tcg_gen_muli_i32(r_tc_off, r_tc_off, sizeof(target_ulong));
-    tcg_gen_ext_i32_ptr(r_tc_off_ptr, r_tc_off);
-    tcg_gen_add_ptr(r_ptr, cpu_env, r_tc_off_ptr);
-    tcg_gen_st_tl(r_tmp, r_ptr, offsetof(CPUState, PC));
-    tcg_temp_free(r_tc_off);
-    tcg_temp_free(r_tc_off_ptr);
-    tcg_temp_free(r_ptr);
+    tcg_gen_st_tl(r_tmp, cpu_env, offsetof(CPUState, active_tc.PC));
     tcg_temp_free(r_tmp);
 }
 
@@ -5202,8 +5182,8 @@
     TCGv t0 = tcg_temp_local_new(TCG_TYPE_TL);
 
     if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 &&
-        ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) !=
-         (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE))))
+        ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) !=
+         (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE))))
         tcg_gen_movi_tl(t0, -1);
     else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
              (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC)))
@@ -5371,8 +5351,8 @@
 
     gen_load_gpr(t0, rt);
     if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 &&
-        ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) !=
-         (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE))))
+        ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) !=
+         (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE))))
         /* NOP */ ;
     else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
              (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC)))
@@ -8009,8 +7989,8 @@
                 "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx
                 " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx
                 " %04x\n",
-                env->PC[env->current_tc], env->HI[env->current_tc][0],
-                env->LO[env->current_tc][0], env->hflags, env->btarget,
+                env->active_tc.PC, env->active_tc.HI[0],
+                env->active_tc.LO[0], env->hflags, env->btarget,
                 env->bcond);
        fpu_dump_state(env, logfile, fprintf, 0);
     }
@@ -8028,18 +8008,18 @@
 {
     int i;
 
-    if (!SIGN_EXT_P(env->PC[env->current_tc]))
-        cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC[env->current_tc]);
-    if (!SIGN_EXT_P(env->HI[env->current_tc][0]))
-        cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI[env->current_tc][0]);
-    if (!SIGN_EXT_P(env->LO[env->current_tc][0]))
-        cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO[env->current_tc][0]);
+    if (!SIGN_EXT_P(env->active_tc.PC))
+        cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->active_tc.PC);
+    if (!SIGN_EXT_P(env->active_tc.HI[0]))
+        cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->active_tc.HI[0]);
+    if (!SIGN_EXT_P(env->active_tc.LO[0]))
+        cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->active_tc.LO[0]);
     if (!SIGN_EXT_P(env->btarget))
         cpu_fprintf(f, "BROKEN: btarget=0x" TARGET_FMT_lx "\n", env->btarget);
 
     for (i = 0; i < 32; i++) {
-        if (!SIGN_EXT_P(env->gpr[env->current_tc][i]))
-            cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[env->current_tc][i]);
+        if (!SIGN_EXT_P(env->active_tc.gpr[i]))
+            cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->active_tc.gpr[i]);
     }
 
     if (!SIGN_EXT_P(env->CP0_EPC))
@@ -8056,11 +8036,11 @@
     int i;
 
     cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n",
-                env->PC[env->current_tc], env->HI[env->current_tc], env->LO[env->current_tc], env->hflags, env->btarget, env->bcond);
+                env->active_tc.PC, env->active_tc.HI, env->active_tc.LO, env->hflags, env->btarget, env->bcond);
     for (i = 0; i < 32; i++) {
         if ((i & 3) == 0)
             cpu_fprintf(f, "GPR%02d:", i);
-        cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[env->current_tc][i]);
+        cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->active_tc.gpr[i]);
         if ((i & 3) == 3)
             cpu_fprintf(f, "\n");
     }
@@ -8085,14 +8065,6 @@
 	return;
 
     cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env");
-    current_tc_gprs = tcg_global_mem_new(TCG_TYPE_PTR,
-                                         TCG_AREG0,
-                                         offsetof(CPUState, current_tc_gprs),
-                                         "current_tc_gprs");
-    current_tc_hi = tcg_global_mem_new(TCG_TYPE_PTR,
-                                       TCG_AREG0,
-                                       offsetof(CPUState, current_tc_hi),
-                                       "current_tc_hi");
     current_fpu = tcg_global_mem_new(TCG_TYPE_PTR,
                                      TCG_AREG0,
                                      offsetof(CPUState, fpu),
@@ -8149,11 +8121,11 @@
     if (env->hflags & MIPS_HFLAG_BMASK) {
         /* If the exception was raised from a delay slot,
          * come back to the jump.  */
-        env->CP0_ErrorEPC = env->PC[env->current_tc] - 4;
+        env->CP0_ErrorEPC = env->active_tc.PC - 4;
     } else {
-        env->CP0_ErrorEPC = env->PC[env->current_tc];
+        env->CP0_ErrorEPC = env->active_tc.PC;
     }
-    env->PC[env->current_tc] = (int32_t)0xBFC00000;
+    env->active_tc.PC = (int32_t)0xBFC00000;
     env->CP0_Wired = 0;
     /* SMP not implemented */
     env->CP0_EBase = 0x80000000;
@@ -8187,7 +8159,7 @@
 void gen_pc_load(CPUState *env, TranslationBlock *tb,
                 unsigned long searched_pc, int pc_pos, void *puc)
 {
-    env->PC[env->current_tc] = gen_opc_pc[pc_pos];
+    env->active_tc.PC = gen_opc_pc[pc_pos];
     env->hflags &= ~MIPS_HFLAG_BMASK;
     env->hflags |= gen_opc_hflags[pc_pos];
 }
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index d84bee0..b7d68cc 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -546,8 +546,6 @@
     env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask;
     env->CP0_SRSCtl = def->CP0_SRSCtl;
     env->current_tc = 0;
-    env->current_tc_gprs = &env->gpr[env->current_tc][0];
-    env->current_tc_hi = &env->HI[env->current_tc][0];
     env->SEGBITS = def->SEGBITS;
     env->SEGMask = (target_ulong)((1ULL << def->SEGBITS) - 1);
 #if defined(TARGET_MIPS64)