]> git.proxmox.com Git - qemu.git/commitdiff
Partial support for 34K multithreading, not functional yet.
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Thu, 6 Sep 2007 00:18:15 +0000 (00:18 +0000)
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Thu, 6 Sep 2007 00:18:15 +0000 (00:18 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3156 c046a42c-6fe2-441c-8c8c-71466251a162

18 files changed:
cpu-exec.c
gdbstub.c
hw/mips_r4k.c
hw/mips_timer.c
linux-user/main.c
linux-user/signal.c
linux-user/syscall.c
monitor.c
target-mips/cpu.h
target-mips/exec.h
target-mips/fop_template.c
target-mips/helper.c
target-mips/op.c
target-mips/op_helper.c
target-mips/op_template.c
target-mips/translate.c
target-mips/translate_init.c
translate-all.c

index 543ec09ef700aebfbc2fde3586feed09bb4ba339..4f1cee616eff139b52a0ecd4ded82469c5e83b7b 100644 (file)
@@ -194,7 +194,7 @@ static inline TranslationBlock *tb_find_fast(void)
 #elif defined(TARGET_MIPS)
     flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
     cs_base = 0;
-    pc = env->PC;
+    pc = env->PC[env->current_tc];
 #elif defined(TARGET_M68K)
     flags = (env->fpcr & M68K_FPCR_PREC)  /* Bit  6 */
             | (env->sr & SR_S)            /* Bit  13 */
index 48c0c56c8455219751630d38becacbc0b06354ec..37347da0b7cdbec09ae69ce0616bdaea43813d35 100644 (file)
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -559,17 +559,17 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
     ptr = mem_buf;
     for (i = 0; i < 32; i++)
       {
-        *(target_ulong *)ptr = tswapl(env->gpr[i]);
+        *(target_ulong *)ptr = tswapl(env->gpr[i][env->current_tc]);
         ptr += sizeof(target_ulong);
       }
 
     *(target_ulong *)ptr = tswapl(env->CP0_Status);
     ptr += sizeof(target_ulong);
 
-    *(target_ulong *)ptr = tswapl(env->LO);
+    *(target_ulong *)ptr = tswapl(env->LO[0][env->current_tc]);
     ptr += sizeof(target_ulong);
 
-    *(target_ulong *)ptr = tswapl(env->HI);
+    *(target_ulong *)ptr = tswapl(env->HI[0][env->current_tc]);
     ptr += sizeof(target_ulong);
 
     *(target_ulong *)ptr = tswapl(env->CP0_BadVAddr);
@@ -578,21 +578,21 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
     *(target_ulong *)ptr = tswapl(env->CP0_Cause);
     ptr += sizeof(target_ulong);
 
-    *(target_ulong *)ptr = tswapl(env->PC);
+    *(target_ulong *)ptr = tswapl(env->PC[env->current_tc]);
     ptr += sizeof(target_ulong);
 
     if (env->CP0_Config1 & (1 << CP0C1_FP))
       {
         for (i = 0; i < 32; i++)
           {
-            *(target_ulong *)ptr = tswapl(env->fpr[i].fs[FP_ENDIAN_IDX]);
+            *(target_ulong *)ptr = tswapl(env->fpu->fpr[i].fs[FP_ENDIAN_IDX]);
             ptr += sizeof(target_ulong);
           }
 
-        *(target_ulong *)ptr = tswapl(env->fcr31);
+        *(target_ulong *)ptr = tswapl(env->fpu->fcr31);
         ptr += sizeof(target_ulong);
 
-        *(target_ulong *)ptr = tswapl(env->fcr0);
+        *(target_ulong *)ptr = tswapl(env->fpu->fcr0);
         ptr += sizeof(target_ulong);
       }
 
@@ -611,7 +611,7 @@ static unsigned int ieee_rm[] =
     float_round_down
   };
 #define RESTORE_ROUNDING_MODE \
-    set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
+    set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status)
 
 static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
 {
@@ -621,17 +621,17 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
     ptr = mem_buf;
     for (i = 0; i < 32; i++)
       {
-        env->gpr[i] = tswapl(*(target_ulong *)ptr);
+        env->gpr[i][env->current_tc] = tswapl(*(target_ulong *)ptr);
         ptr += sizeof(target_ulong);
       }
 
     env->CP0_Status = tswapl(*(target_ulong *)ptr);
     ptr += sizeof(target_ulong);
 
-    env->LO = tswapl(*(target_ulong *)ptr);
+    env->LO[0][env->current_tc] = tswapl(*(target_ulong *)ptr);
     ptr += sizeof(target_ulong);
 
-    env->HI = tswapl(*(target_ulong *)ptr);
+    env->HI[0][env->current_tc] = tswapl(*(target_ulong *)ptr);
     ptr += sizeof(target_ulong);
 
     env->CP0_BadVAddr = tswapl(*(target_ulong *)ptr);
@@ -640,21 +640,21 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
     env->CP0_Cause = tswapl(*(target_ulong *)ptr);
     ptr += sizeof(target_ulong);
 
-    env->PC = tswapl(*(target_ulong *)ptr);
+    env->PC[env->current_tc] = tswapl(*(target_ulong *)ptr);
     ptr += sizeof(target_ulong);
 
     if (env->CP0_Config1 & (1 << CP0C1_FP))
       {
         for (i = 0; i < 32; i++)
           {
-            env->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr);
+            env->fpu->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr);
             ptr += sizeof(target_ulong);
           }
 
-        env->fcr31 = tswapl(*(target_ulong *)ptr) & 0x0183FFFF;
+        env->fpu->fcr31 = tswapl(*(target_ulong *)ptr) & 0x0183FFFF;
         ptr += sizeof(target_ulong);
 
-        env->fcr0 = tswapl(*(target_ulong *)ptr);
+        env->fpu->fcr0 = tswapl(*(target_ulong *)ptr);
         ptr += sizeof(target_ulong);
 
         /* set rounding mode */
@@ -775,7 +775,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
 #elif defined (TARGET_SH4)
             env->pc = addr;
 #elif defined (TARGET_MIPS)
-            env->PC = addr;
+            env->PC[env->current_tc] = addr;
 #endif
         }
 #ifdef CONFIG_USER_ONLY
@@ -799,7 +799,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
 #elif defined (TARGET_SH4)
             env->pc = addr;
 #elif defined (TARGET_MIPS)
-            env->PC = addr;
+            env->PC[env->current_tc] = addr;
 #endif
         }
         cpu_single_step(env, 1);
index 2208922a7578b37232f4e529dd87ae8307bb7ebc..82782273b5b5e071c18650d9a932527f3995a2fb 100644 (file)
@@ -77,7 +77,7 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename,
     if (kernel_size >= 0) {
         if ((entry & ~0x7fffffffULL) == 0x80000000)
             entry = (int32_t)entry;
-        env->PC = entry;
+        env->PC[env->current_tc] = entry;
     } else {
         fprintf(stderr, "qemu: could not load kernel '%s'\n",
                 kernel_filename);
index 6a517e184190d1dd527a148424f5cae05d1713bd..2fe5e29c58b453ad64190cc25de235941b2a2c35 100644 (file)
@@ -10,7 +10,7 @@ uint32_t cpu_mips_get_random (CPUState *env)
     static uint32_t seed = 0;
     uint32_t idx;
     seed = seed * 314159 + 1;
-    idx = (seed >> 16) % (env->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
+    idx = (seed >> 16) % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
     return idx;
 }
 
index 32fa43d47634dd8c43c3fe542a6c9eee96b7e830..edcb68b8d43ef1db9c7153ba81921d63e5eaa208 100644 (file)
@@ -1374,8 +1374,8 @@ void cpu_loop(CPUMIPSState *env)
         trapnr = cpu_mips_exec(env);
         switch(trapnr) {
         case EXCP_SYSCALL:
-            syscall_num = env->gpr[2] - 4000;
-            env->PC += 4;
+            syscall_num = env->gpr[2][env->current_tc] - 4000;
+            env->PC[env->current_tc] += 4;
             if (syscall_num >= sizeof(mips_syscall_args)) {
                 ret = -ENOSYS;
             } else {
@@ -1384,7 +1384,7 @@ void cpu_loop(CPUMIPSState *env)
                 target_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
 
                 nb_args = mips_syscall_args[syscall_num];
-                sp_reg = env->gpr[29];
+                sp_reg = env->gpr[29][env->current_tc];
                 switch (nb_args) {
                 /* these arguments are taken from the stack */
                 case 8: arg8 = tgetl(sp_reg + 28);
@@ -1394,18 +1394,20 @@ void cpu_loop(CPUMIPSState *env)
                 default:
                     break;
                 }
-                ret = do_syscall(env, env->gpr[2],
-                                 env->gpr[4], env->gpr[5],
-                                 env->gpr[6], env->gpr[7],
+                ret = do_syscall(env, env->gpr[2][env->current_tc],
+                                 env->gpr[4][env->current_tc],
+                                 env->gpr[5][env->current_tc],
+                                 env->gpr[6][env->current_tc],
+                                 env->gpr[7][env->current_tc],
                                  arg5, arg6/*, arg7, arg8*/);
             }
             if ((unsigned int)ret >= (unsigned int)(-1133)) {
-                env->gpr[7] = 1; /* error flag */
+                env->gpr[7][env->current_tc] = 1; /* error flag */
                 ret = -ret;
             } else {
-                env->gpr[7] = 0; /* error flag */
+                env->gpr[7][env->current_tc] = 0; /* error flag */
             }
-            env->gpr[2] = ret;
+            env->gpr[2][env->current_tc] = ret;
             break;
         case EXCP_TLBL:
         case EXCP_TLBS:
@@ -2053,9 +2055,9 @@ int main(int argc, char **argv)
         cpu_mips_register(env, def);
 
         for(i = 0; i < 32; i++) {
-            env->gpr[i] = regs->regs[i];
+            env->gpr[i][env->current_tc] = regs->regs[i];
         }
-        env->PC = regs->cp0_epc;
+        env->PC[env->current_tc] = regs->cp0_epc;
     }
 #elif defined(TARGET_SH4)
     {
index eea73470faef2d18e96b6054e64e4a02476e3d68..f73d50516f8540b5698c8c69482ca24ebbbb0061 100644 (file)
@@ -1686,10 +1686,10 @@ setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
 {
     int err = 0;
 
-    err |= __put_user(regs->PC, &sc->sc_pc);
+    err |= __put_user(regs->PC[regs->current_tc], &sc->sc_pc);
 
-#define save_gp_reg(i) do {                                    \
-        err |= __put_user(regs->gpr[i], &sc->sc_regs[i]);      \
+#define save_gp_reg(i) do {                                                    \
+        err |= __put_user(regs->gpr[i][regs->current_tc], &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);
@@ -1702,8 +1702,8 @@ setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
     save_gp_reg(31);
 #undef save_gp_reg
 
-    err |= __put_user(regs->HI, &sc->sc_mdhi);
-    err |= __put_user(regs->LO, &sc->sc_mdlo);
+    err |= __put_user(regs->HI[0][regs->current_tc], &sc->sc_mdhi);
+    err |= __put_user(regs->LO[0][regs->current_tc], &sc->sc_mdlo);
 
     /* Not used yet, but might be useful if we ever have DSP suppport */
 #if 0
@@ -1763,11 +1763,11 @@ restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
 
     err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
 
-    err |= __get_user(regs->HI, &sc->sc_mdhi);
-    err |= __get_user(regs->LO, &sc->sc_mdlo);
+    err |= __get_user(regs->HI[0][regs->current_tc], &sc->sc_mdhi);
+    err |= __get_user(regs->LO[0][regs->current_tc], &sc->sc_mdlo);
 
-#define restore_gp_reg(i) do {                                         \
-        err |= __get_user(regs->gpr[i], &sc->sc_regs[i]);              \
+#define restore_gp_reg(i) do {                                                         \
+        err |= __get_user(regs->gpr[i][regs->current_tc], &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);
@@ -1833,7 +1833,7 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size)
     unsigned long sp;
 
     /* Default to using normal stack */
-    sp = regs->gpr[29];
+    sp = regs->gpr[29][regs->current_tc];
 
     /*
      * FPU emulator may have it's own trampoline active just
@@ -1881,15 +1881,15 @@ static void setup_frame(int sig, struct emulated_sigaction * ka,
     * $25 and PC point to the signal handler, $29 points to the
     * struct sigframe.
     */
-    regs->gpr[ 4] = sig;
-    regs->gpr[ 5] = 0;
-    regs->gpr[ 6] = h2g(&frame->sf_sc);
-    regs->gpr[29] = h2g(frame);
-    regs->gpr[31] = h2g(frame->sf_code);
+    regs->gpr[ 4][regs->current_tc] = sig;
+    regs->gpr[ 5][regs->current_tc] = 0;
+    regs->gpr[ 6][regs->current_tc] = h2g(&frame->sf_sc);
+    regs->gpr[29][regs->current_tc] = h2g(frame);
+    regs->gpr[31][regs->current_tc] = h2g(frame->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->gpr[25] = ka->sa._sa_handler;
+    regs->PC[regs->current_tc] = regs->gpr[25][regs->current_tc] = ka->sa._sa_handler;
     return;
 
 give_sigsegv:
@@ -1907,7 +1907,7 @@ long do_sigreturn(CPUState *regs)
 #if defined(DEBUG_SIGNAL)
     fprintf(stderr, "do_sigreturn\n");
 #endif
-    frame = (struct sigframe *) regs->gpr[29];
+    frame = (struct sigframe *) regs->gpr[29][regs->current_tc];
     if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
        goto badframe;
 
@@ -1934,7 +1934,7 @@ long do_sigreturn(CPUState *regs)
     /* Unreached */
 #endif
     
-    regs->PC = regs->CP0_EPC;
+    regs->PC[regs->current_tc] = 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;
index e23a684e763c983e07e77201670c4faa2033b048..cd956aa1ac69816ee9813f18b2be65b020ce1057 100644 (file)
@@ -2189,8 +2189,8 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
         /* ??? is this sufficient?  */
 #elif defined(TARGET_MIPS)
         if (!newsp)
-            newsp = env->gpr[29];
-        new_env->gpr[29] = newsp;
+            newsp = env->gpr[29][env->current_tc];
+        new_env->gpr[29][env->current_tc] = newsp;
 #elif defined(TARGET_PPC)
         if (!newsp)
             newsp = env->gpr[1];
@@ -2777,7 +2777,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
             ret = get_errno(pipe(host_pipe));
             if (!is_error(ret)) {
 #if defined(TARGET_MIPS)
-               ((CPUMIPSState*)cpu_env)->gpr[3] = host_pipe[1];
+                CPUMIPSState *env = (CPUMIPSState*)cpu_env;
+               env->gpr[3][env->current_tc] = host_pipe[1];
                ret = host_pipe[0];
 #else
                 tput32(arg1, host_pipe[0]);
index 3b9408b557e055a69e20383e5dcf99841a2c4333..9ff63130dc25e5c24693ad0090324a80a9e359d5 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -309,6 +309,10 @@ static void do_info_cpus(void)
         term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc);
         if (env->halted)
             term_printf(" (halted)");
+#elif defined(TARGET_MIPS)
+        term_printf(" PC=0x" TARGET_FMT_lx, env->PC[env->current_tc]);
+        if (env->halted)
+            term_printf(" (halted)");
 #endif
         term_printf("\n");
     }
index f5f35e12239a4ebce67248d61d94c67de3389b6a..f8b4b185830cdfcc6c02e9134348a85d40eed40b 100644 (file)
@@ -17,21 +17,7 @@ typedef unsigned char           uint_fast8_t;
 typedef unsigned int            uint_fast16_t;
 #endif
 
-typedef union fpr_t fpr_t;
-union fpr_t {
-    float64  fd;   /* ieee double precision */
-    float32  fs[2];/* ieee single precision */
-    uint64_t d;    /* binary double fixed-point */
-    uint32_t w[2]; /* binary single fixed-point */
-};
-/* define FP_ENDIAN_IDX to access the same location
- * in the fpr_t union regardless of the host endianess
- */
-#if defined(WORDS_BIGENDIAN)
-#  define FP_ENDIAN_IDX 1
-#else
-#  define FP_ENDIAN_IDX 0
-#endif
+struct CPUMIPSState;
 
 typedef struct r4k_tlb_t r4k_tlb_t;
 struct r4k_tlb_t {
@@ -48,20 +34,40 @@ struct r4k_tlb_t {
     target_ulong PFN[2];
 };
 
-typedef struct mips_def_t mips_def_t;
+typedef struct CPUMIPSTLBContext CPUMIPSTLBContext;
+struct CPUMIPSTLBContext {
+    uint32_t nb_tlb;
+    uint32_t tlb_in_use;
+    int (*map_address) (struct CPUMIPSState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type);
+    void (*do_tlbwi) (void);
+    void (*do_tlbwr) (void);
+    void (*do_tlbp) (void);
+    void (*do_tlbr) (void);
+    union {
+        struct {
+            r4k_tlb_t tlb[MIPS_TLB_MAX];
+        } r4k;
+    } mmu;
+};
 
-typedef struct CPUMIPSState CPUMIPSState;
-struct CPUMIPSState {
-    /* General integer registers */
-    target_ulong gpr[32];
-    /* Special registers */
-    target_ulong PC;
-#if TARGET_LONG_BITS > HOST_LONG_BITS
-    target_ulong t0;
-    target_ulong t1;
-    target_ulong t2;
+typedef union fpr_t fpr_t;
+union fpr_t {
+    float64  fd;   /* ieee double precision */
+    float32  fs[2];/* ieee single precision */
+    uint64_t d;    /* binary double fixed-point */
+    uint32_t w[2]; /* binary single fixed-point */
+};
+/* define FP_ENDIAN_IDX to access the same location
+ * in the fpr_t union regardless of the host endianess
+ */
+#if defined(WORDS_BIGENDIAN)
+#  define FP_ENDIAN_IDX 1
+#else
+#  define FP_ENDIAN_IDX 0
 #endif
-    target_ulong HI, LO;
+
+typedef struct CPUMIPSFPUContext CPUMIPSFPUContext;
+struct CPUMIPSFPUContext {
     /* Floating point registers */
     fpr_t fpr[32];
 #ifndef USE_HOST_FLOAT_REGS
@@ -99,30 +105,161 @@ struct CPUMIPSState {
 #define FP_DIV0           8
 #define FP_INVALID        16
 #define FP_UNIMPLEMENTED  32
+};
+
+typedef struct CPUMIPSMVPContext CPUMIPSMVPContext;
+struct CPUMIPSMVPContext {
+    int32_t CP0_MVPControl;
+#define CP0MVPCo_CPA   3
+#define CP0MVPCo_STLB  2
+#define CP0MVPCo_VPC   1
+#define CP0MVPCo_EVP   0
+    int32_t CP0_MVPConf0;
+#define CP0MVPC0_M     31
+#define CP0MVPC0_TLBS  29
+#define CP0MVPC0_GS    28
+#define CP0MVPC0_PCP   27
+#define CP0MVPC0_PTLBE 16
+#define CP0MVPC0_TCA   15
+#define CP0MVPC0_PVPE  10
+#define CP0MVPC0_PTC   0
+    int32_t CP0_MVPConf1;
+#define CP0MVPC1_CIM   31
+#define CP0MVPC1_CIF   30
+#define CP0MVPC1_PCX   20
+#define CP0MVPC1_PCP2  10
+#define CP0MVPC1_PCP1  0
+};
+
+typedef struct mips_def_t mips_def_t;
+
+#define MIPS_SHADOW_SET_MAX 16
+#define MIPS_TC_MAX 5
+#define MIPS_DSP_ACC 4
+
+typedef struct CPUMIPSState CPUMIPSState;
+struct CPUMIPSState {
+    /* General integer registers */
+    target_ulong gpr[32][MIPS_SHADOW_SET_MAX];
+    /* Special registers */
+    target_ulong PC[MIPS_TC_MAX];
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+    target_ulong t0;
+    target_ulong t1;
+    target_ulong t2;
+#endif
+    target_ulong HI[MIPS_DSP_ACC][MIPS_TC_MAX];
+    target_ulong LO[MIPS_DSP_ACC][MIPS_TC_MAX];
+    target_ulong ACX[MIPS_DSP_ACC][MIPS_TC_MAX];
+    target_ulong DSPControl[MIPS_TC_MAX];
+
+    CPUMIPSMVPContext *mvp;
+    CPUMIPSTLBContext *tlb;
+    CPUMIPSFPUContext *fpu;
+    uint32_t current_tc;
 
-    uint32_t nb_tlb;
-    uint32_t tlb_in_use;
     uint32_t SEGBITS;
     target_ulong SEGMask;
-    int (*map_address) (CPUMIPSState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type);
-    void (*do_tlbwi) (void);
-    void (*do_tlbwr) (void);
-    void (*do_tlbp) (void);
-    void (*do_tlbr) (void);
-    union {
-        struct {
-            r4k_tlb_t tlb[MIPS_TLB_MAX];
-        } r4k;
-    } mmu;
 
     int32_t CP0_Index;
+    /* CP0_MVP* are per MVP registers. */
     int32_t CP0_Random;
+    int32_t CP0_VPEControl;
+#define CP0VPECo_YSI   21
+#define CP0VPECo_GSI   20
+#define CP0VPECo_EXCPT 16
+#define CP0VPECo_TE    15
+#define CP0VPECo_TargTC        0
+    int32_t CP0_VPEConf0;
+#define CP0VPEC0_M     31
+#define CP0VPEC0_XTC   21
+#define CP0VPEC0_TCS   19
+#define CP0VPEC0_SCS   18
+#define CP0VPEC0_DSC   17
+#define CP0VPEC0_ICS   16
+#define CP0VPEC0_MVP   1
+#define CP0VPEC0_VPA   0
+    int32_t CP0_VPEConf1;
+#define CP0VPEC1_NCX   20
+#define CP0VPEC1_NCP2  10
+#define CP0VPEC1_NCP1  0
+    target_ulong CP0_YQMask;
+    target_ulong CP0_VPESchedule;
+    target_ulong CP0_VPEScheFBack;
+    int32_t CP0_VPEOpt;
+#define CP0VPEOpt_IWX7 15
+#define CP0VPEOpt_IWX6 14
+#define CP0VPEOpt_IWX5 13
+#define CP0VPEOpt_IWX4 12
+#define CP0VPEOpt_IWX3 11
+#define CP0VPEOpt_IWX2 10
+#define CP0VPEOpt_IWX1 9
+#define CP0VPEOpt_IWX0 8
+#define CP0VPEOpt_DWX7 7
+#define CP0VPEOpt_DWX6 6
+#define CP0VPEOpt_DWX5 5
+#define CP0VPEOpt_DWX4 4
+#define CP0VPEOpt_DWX3 3
+#define CP0VPEOpt_DWX2 2
+#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;
     int32_t CP0_PageGrain;
     int32_t CP0_Wired;
+    int32_t CP0_SRSConf0_rw_bitmask;
+    int32_t CP0_SRSConf0;
+#define CP0SRSC0_M     31
+#define CP0SRSC0_SRS3  20
+#define CP0SRSC0_SRS2  10
+#define CP0SRSC0_SRS1  0
+    int32_t CP0_SRSConf1_rw_bitmask;
+    int32_t CP0_SRSConf1;
+#define CP0SRSC1_M     31
+#define CP0SRSC1_SRS6  20
+#define CP0SRSC1_SRS5  10
+#define CP0SRSC1_SRS4  0
+    int32_t CP0_SRSConf2_rw_bitmask;
+    int32_t CP0_SRSConf2;
+#define CP0SRSC2_M     31
+#define CP0SRSC2_SRS9  20
+#define CP0SRSC2_SRS8  10
+#define CP0SRSC2_SRS7  0
+    int32_t CP0_SRSConf3_rw_bitmask;
+    int32_t CP0_SRSConf3;
+#define CP0SRSC3_M     31
+#define CP0SRSC3_SRS12 20
+#define CP0SRSC3_SRS11 10
+#define CP0SRSC3_SRS10 0
+    int32_t CP0_SRSConf4_rw_bitmask;
+    int32_t CP0_SRSConf4;
+#define CP0SRSC4_SRS15 20
+#define CP0SRSC4_SRS14 10
+#define CP0SRSC4_SRS13 0
     int32_t CP0_HWREna;
     target_ulong CP0_BadVAddr;
     int32_t CP0_Count;
@@ -152,8 +289,24 @@ struct CPUMIPSState {
 #define CP0St_EXL   1
 #define CP0St_IE    0
     int32_t CP0_IntCtl;
+#define CP0IntCtl_IPTI 29
+#define CP0IntCtl_IPPC1 26
+#define CP0IntCtl_VS 5
     int32_t CP0_SRSCtl;
+#define CP0SRSCtl_HSS 26
+#define CP0SRSCtl_EICSS 18
+#define CP0SRSCtl_ESS 12
+#define CP0SRSCtl_PSS 6
+#define CP0SRSCtl_CSS 0
     int32_t CP0_SRSMap;
+#define CP0SRSMap_SSV7 28
+#define CP0SRSMap_SSV6 24
+#define CP0SRSMap_SSV5 20
+#define CP0SRSMap_SSV4 16
+#define CP0SRSMap_SSV3 12
+#define CP0SRSMap_SSV2 8
+#define CP0SRSMap_SSV1 4
+#define CP0SRSMap_SSV0 0
     int32_t CP0_Cause;
 #define CP0Ca_BD   31
 #define CP0Ca_TI   30
@@ -219,13 +372,14 @@ struct CPUMIPSState {
 #define CP0C3_TL   0
     int32_t CP0_Config6;
     int32_t CP0_Config7;
+    /* XXX: Maybe make LLAddr per-TC? */
     target_ulong CP0_LLAddr;
     target_ulong CP0_WatchLo[8];
     int32_t CP0_WatchHi[8];
     target_ulong CP0_XContext;
     int32_t CP0_Framemask;
     int32_t CP0_Debug;
-#define CPDB_DBD   31
+#define CP0DB_DBD  31
 #define CP0DB_DM   30
 #define CP0DB_LSNM 28
 #define CP0DB_Doze 27
@@ -243,6 +397,7 @@ struct CPUMIPSState {
 #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;
@@ -284,7 +439,8 @@ struct CPUMIPSState {
 
     int SYNCI_Step; /* Address step size for SYNCI */
     int CCRes; /* Cycle count resolution/divisor */
-    int Status_rw_bitmask; /* Read/write bits in CP0_Status */
+    uint32_t CP0_Status_rw_bitmask; /* Read/write bits in CP0_Status */
+    uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */
 
 #ifdef CONFIG_USER_ONLY
     target_ulong tls_value;
@@ -376,6 +532,7 @@ enum {
     EXCP_TLBS,
     EXCP_DBE,
     EXCP_DDBL,
+    EXCP_THREAD,
     EXCP_MTCP0         = 0x104, /* mtmsr instruction:               */
                                 /* may change privilege level       */
     EXCP_BRANCH        = 0x108, /* branch instruction               */
index 5b0c833848d99f4b6ab62a7978c05769e7f2b941..53c4189a519b7508271ec1e18e8414a5a18ac78e 100644 (file)
@@ -23,24 +23,24 @@ register target_ulong T2 asm(AREG3);
 #if defined (USE_HOST_FLOAT_REGS)
 #error "implement me."
 #else
-#define FDT0 (env->ft0.fd)
-#define FDT1 (env->ft1.fd)
-#define FDT2 (env->ft2.fd)
-#define FST0 (env->ft0.fs[FP_ENDIAN_IDX])
-#define FST1 (env->ft1.fs[FP_ENDIAN_IDX])
-#define FST2 (env->ft2.fs[FP_ENDIAN_IDX])
-#define FSTH0 (env->ft0.fs[!FP_ENDIAN_IDX])
-#define FSTH1 (env->ft1.fs[!FP_ENDIAN_IDX])
-#define FSTH2 (env->ft2.fs[!FP_ENDIAN_IDX])
-#define DT0 (env->ft0.d)
-#define DT1 (env->ft1.d)
-#define DT2 (env->ft2.d)
-#define WT0 (env->ft0.w[FP_ENDIAN_IDX])
-#define WT1 (env->ft1.w[FP_ENDIAN_IDX])
-#define WT2 (env->ft2.w[FP_ENDIAN_IDX])
-#define WTH0 (env->ft0.w[!FP_ENDIAN_IDX])
-#define WTH1 (env->ft1.w[!FP_ENDIAN_IDX])
-#define WTH2 (env->ft2.w[!FP_ENDIAN_IDX])
+#define FDT0 (env->fpu->ft0.fd)
+#define FDT1 (env->fpu->ft1.fd)
+#define FDT2 (env->fpu->ft2.fd)
+#define FST0 (env->fpu->ft0.fs[FP_ENDIAN_IDX])
+#define FST1 (env->fpu->ft1.fs[FP_ENDIAN_IDX])
+#define FST2 (env->fpu->ft2.fs[FP_ENDIAN_IDX])
+#define FSTH0 (env->fpu->ft0.fs[!FP_ENDIAN_IDX])
+#define FSTH1 (env->fpu->ft1.fs[!FP_ENDIAN_IDX])
+#define FSTH2 (env->fpu->ft2.fs[!FP_ENDIAN_IDX])
+#define DT0 (env->fpu->ft0.d)
+#define DT1 (env->fpu->ft1.d)
+#define DT2 (env->fpu->ft2.d)
+#define WT0 (env->fpu->ft0.w[FP_ENDIAN_IDX])
+#define WT1 (env->fpu->ft1.w[FP_ENDIAN_IDX])
+#define WT2 (env->fpu->ft2.w[FP_ENDIAN_IDX])
+#define WTH0 (env->fpu->ft0.w[!FP_ENDIAN_IDX])
+#define WTH1 (env->fpu->ft1.w[!FP_ENDIAN_IDX])
+#define WTH2 (env->fpu->ft2.w[!FP_ENDIAN_IDX])
 #endif
 
 #if defined (DEBUG_OP)
@@ -157,7 +157,8 @@ void cpu_mips_update_irq (CPUState *env);
 void cpu_mips_clock_init (CPUState *env);
 void cpu_mips_tlb_flush (CPUState *env, int flush_global);
 
-void do_ctc1 (void);
+void do_cfc1 (int reg);
+void do_ctc1 (int reg);
 
 #define FOP_PROTO(op)              \
 void do_float_ ## op ## _s(void);  \
index 0f1595ff87d6e123e0512f30d813f2d43cf87ed4..bbdcb28903fd1ba788a2afd143f66a3e5fea5c78 100644 (file)
 #define OP_WLOAD_FREG(treg, tregname, FREG)              \
     void glue(glue(op_load_fpr_,tregname), FREG) (void)  \
     {                                                    \
-        treg = env->fpr[FREG].fs[FP_ENDIAN_IDX];         \
+        treg = env->fpu->fpr[FREG].fs[FP_ENDIAN_IDX];    \
         RETURN();                                        \
     }
 
 #define OP_WSTORE_FREG(treg, tregname, FREG)             \
     void glue(glue(op_store_fpr_,tregname), FREG) (void) \
     {                                                    \
-        env->fpr[FREG].fs[FP_ENDIAN_IDX] = treg;         \
+        env->fpu->fpr[FREG].fs[FP_ENDIAN_IDX] = treg;    \
         RETURN();                                        \
     }
 
@@ -50,10 +50,10 @@ OP_WSTORE_FREG(WT2, WT2_fpr, FREG)
     void glue(glue(op_load_fpr_,tregname), FREG) (void)  \
     {                                                    \
         if (env->hflags & MIPS_HFLAG_F64)                \
-            treg = env->fpr[FREG].fd;                    \
+            treg = env->fpu->fpr[FREG].fd;               \
         else                                             \
-            treg = (uint64_t)(env->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \
-                   env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \
+            treg = (uint64_t)(env->fpu->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \
+                   env->fpu->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \
         RETURN();                                        \
     }
 
@@ -61,10 +61,10 @@ OP_WSTORE_FREG(WT2, WT2_fpr, FREG)
     void glue(glue(op_store_fpr_,tregname), FREG) (void) \
     {                                                    \
         if (env->hflags & MIPS_HFLAG_F64)                \
-            env->fpr[FREG].fd = treg;                    \
+            env->fpu->fpr[FREG].fd = treg;               \
         else {                                           \
-            env->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \
-            env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg; \
+            env->fpu->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \
+            env->fpu->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg;      \
         }                                                \
         RETURN();                                        \
     }
@@ -81,14 +81,14 @@ OP_DSTORE_FREG(DT2, DT2_fpr, FREG)
 #define OP_PSLOAD_FREG(treg, tregname, FREG)             \
     void glue(glue(op_load_fpr_,tregname), FREG) (void)  \
     {                                                    \
-        treg = env->fpr[FREG].fs[!FP_ENDIAN_IDX];        \
+        treg = env->fpu->fpr[FREG].fs[!FP_ENDIAN_IDX];   \
         RETURN();                                        \
     }
 
 #define OP_PSSTORE_FREG(treg, tregname, FREG)            \
     void glue(glue(op_store_fpr_,tregname), FREG) (void) \
     {                                                    \
-        env->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg;        \
+        env->fpu->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg;   \
         RETURN();                                        \
     }
 
index 1c83704705669909d965e5f687cf75923e622445..6d0be1015613a14921dc6c5fab8bea7d0e1671ab 100644 (file)
@@ -70,8 +70,8 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot,
     uint8_t ASID = env->CP0_EntryHi & 0xFF;
     int i;
 
-    for (i = 0; i < env->tlb_in_use; i++) {
-        r4k_tlb_t *tlb = &env->mmu.r4k.tlb[i];
+    for (i = 0; i < env->tlb->tlb_in_use; i++) {
+        r4k_tlb_t *tlb = &env->tlb->mmu.r4k.tlb[i];
         /* 1k pages are not supported. */
         target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
         target_ulong tag = address & ~mask;
@@ -134,7 +134,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
             *physical = address & 0xFFFFFFFF;
             *prot = PAGE_READ | PAGE_WRITE;
         } else {
-            ret = env->map_address(env, physical, prot, address, rw, access_type);
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
         }
 #ifdef TARGET_MIPS64
 /*
@@ -144,14 +144,14 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
     } else if (address < 0x3FFFFFFFFFFFFFFFULL) {
         /* xuseg */
        if (UX && address < (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) {
-            ret = env->map_address(env, physical, prot, address, rw, access_type);
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
        } else {
            ret = TLBRET_BADADDR;
         }
     } else if (address < 0x7FFFFFFFFFFFFFFFULL) {
         /* xsseg */
        if (SX && address < (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) {
-            ret = env->map_address(env, physical, prot, address, rw, access_type);
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
        } else {
            ret = TLBRET_BADADDR;
         }
@@ -169,7 +169,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
         /* xkseg */
         /* XXX: check supervisor mode */
        if (KX && address < (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) {
-            ret = env->map_address(env, physical, prot, address, rw, access_type);
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
        } else {
            ret = TLBRET_BADADDR;
        }
@@ -186,12 +186,12 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
         *prot = PAGE_READ | PAGE_WRITE;
     } else if (address < (int32_t)0xE0000000UL) {
         /* kseg2 */
-        ret = env->map_address(env, physical, prot, address, rw, access_type);
+        ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
     } else {
         /* kseg3 */
         /* XXX: check supervisor mode */
         /* XXX: debug segment is not emulated */
-        ret = env->map_address(env, physical, prot, address, rw, access_type);
+        ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
     }
 #if 0
     if (logfile) {
@@ -238,7 +238,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
         cpu_dump_state(env, logfile, fprintf, 0);
 #endif
         fprintf(logfile, "%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d is_user %d smmu %d\n",
-                __func__, env->PC, address, rw, is_user, is_softmmu);
+                __func__, env->PC[env->current_tc], address, rw, is_user, is_softmmu);
     }
 
     rw &= 1;
@@ -328,7 +328,7 @@ void do_interrupt (CPUState *env)
 
     if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
         fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n",
-                __func__, env->PC, env->CP0_EPC, cause, env->exception_index);
+                __func__, env->PC[env->current_tc], env->CP0_EPC, cause, env->exception_index);
     }
     if (env->exception_index == EXCP_EXT_INTERRUPT &&
         (env->hflags & MIPS_HFLAG_DM))
@@ -342,7 +342,7 @@ void do_interrupt (CPUState *env)
          * (but we assume the pc has always been updated during
          *  code translation).
          */
-        env->CP0_DEPC = env->PC;
+        env->CP0_DEPC = env->PC[env->current_tc];
         goto enter_debug_mode;
     case EXCP_DINT:
         env->CP0_Debug |= 1 << CP0DB_DINT;
@@ -362,10 +362,10 @@ void do_interrupt (CPUState *env)
         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 - 4;
+            env->CP0_DEPC = env->PC[env->current_tc] - 4;
             env->hflags &= ~MIPS_HFLAG_BMASK;
         } else {
-            env->CP0_DEPC = env->PC;
+            env->CP0_DEPC = env->PC[env->current_tc];
         }
     enter_debug_mode:
         env->hflags |= MIPS_HFLAG_DM;
@@ -375,7 +375,7 @@ void do_interrupt (CPUState *env)
         /* EJTAG probe trap enable is not implemented... */
         if (!(env->CP0_Status & (1 << CP0St_EXL)))
             env->CP0_Cause &= ~(1 << CP0Ca_BD);
-        env->PC = (int32_t)0xBFC00480;
+        env->PC[env->current_tc] = (int32_t)0xBFC00480;
         break;
     case EXCP_RESET:
         cpu_reset(env);
@@ -390,10 +390,10 @@ void do_interrupt (CPUState *env)
         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 - 4;
+            env->CP0_ErrorEPC = env->PC[env->current_tc] - 4;
             env->hflags &= ~MIPS_HFLAG_BMASK;
         } else {
-            env->CP0_ErrorEPC = env->PC;
+            env->CP0_ErrorEPC = env->PC[env->current_tc];
         }
         env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
         if ((env->CP0_Config0 & (0x3 << CP0C0_AT)))
@@ -401,7 +401,7 @@ void do_interrupt (CPUState *env)
         env->hflags &= ~MIPS_HFLAG_UM;
         if (!(env->CP0_Status & (1 << CP0St_EXL)))
             env->CP0_Cause &= ~(1 << CP0Ca_BD);
-        env->PC = (int32_t)0xBFC00000;
+        env->PC[env->current_tc] = (int32_t)0xBFC00000;
         break;
     case EXCP_MCHECK:
         cause = 24;
@@ -471,6 +471,9 @@ void do_interrupt (CPUState *env)
         goto set_EPC;
     case EXCP_TLBS:
         cause = 3;
+        goto set_EPC;
+    case EXCP_THREAD:
+        cause = 25;
         if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
 #ifdef TARGET_MIPS64
             int R = env->CP0_BadVAddr >> 62;
@@ -489,10 +492,10 @@ void do_interrupt (CPUState *env)
             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 - 4;
+                env->CP0_EPC = env->PC[env->current_tc] - 4;
                 env->CP0_Cause |= (1 << CP0Ca_BD);
             } else {
-                env->CP0_EPC = env->PC;
+                env->CP0_EPC = env->PC[env->current_tc];
                 env->CP0_Cause &= ~(1 << CP0Ca_BD);
             }
             env->CP0_Status |= (1 << CP0St_EXL);
@@ -502,11 +505,11 @@ void do_interrupt (CPUState *env)
         }
         env->hflags &= ~MIPS_HFLAG_BMASK;
         if (env->CP0_Status & (1 << CP0St_BEV)) {
-            env->PC = (int32_t)0xBFC00200;
+            env->PC[env->current_tc] = (int32_t)0xBFC00200;
         } else {
-            env->PC = (int32_t)(env->CP0_EBase & ~0x3ff);
+            env->PC[env->current_tc] = (int32_t)(env->CP0_EBase & ~0x3ff);
         }
-        env->PC += offset;
+        env->PC[env->current_tc] += offset;
         env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
         break;
     default:
@@ -520,7 +523,7 @@ void do_interrupt (CPUState *env)
     if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
         fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n"
                 "    S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
-                __func__, env->PC, env->CP0_EPC, cause, env->exception_index,
+                __func__, env->PC[env->current_tc], env->CP0_EPC, cause, env->exception_index,
                 env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
                 env->CP0_DEPC);
     }
@@ -536,19 +539,19 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
     uint8_t ASID = env->CP0_EntryHi & 0xFF;
     target_ulong mask;
 
-    tlb = &env->mmu.r4k.tlb[idx];
+    tlb = &env->tlb->mmu.r4k.tlb[idx];
     /* The qemu TLB is flushed when the ASID changes, so no need to
        flush these entries again.  */
     if (tlb->G == 0 && tlb->ASID != ASID) {
         return;
     }
 
-    if (use_extra && env->tlb_in_use < MIPS_TLB_MAX) {
+    if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) {
         /* For tlbwr, we can shadow the discarded entry into
           a new (fake) TLB entry, as long as the guest can not
           tell that it's there.  */
-        env->mmu.r4k.tlb[env->tlb_in_use] = *tlb;
-        env->tlb_in_use++;
+        env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb;
+        env->tlb->tlb_in_use++;
         return;
     }
 
index 12498d033507d3ad083dbac0a5ecc8f04d95fa14..3f52f59d34ee94b3fef8aef65eac75634bdf2374 100644 (file)
@@ -254,25 +254,25 @@ void op_dup_T0 (void)
 
 void op_load_HI (void)
 {
-    T0 = env->HI;
+    T0 = env->HI[PARAM1][env->current_tc];
     RETURN();
 }
 
 void op_store_HI (void)
 {
-    env->HI = T0;
+    env->HI[PARAM1][env->current_tc] = T0;
     RETURN();
 }
 
 void op_load_LO (void)
 {
-    T0 = env->LO;
+    T0 = env->LO[PARAM1][env->current_tc];
     RETURN();
 }
 
 void op_store_LO (void)
 {
-    env->LO = T0;
+    env->LO[PARAM1][env->current_tc] = T0;
     RETURN();
 }
 
@@ -363,8 +363,8 @@ void op_div (void)
 void op_div (void)
 {
     if (T1 != 0) {
-        env->LO = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1);
-        env->HI = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1);
+        env->LO[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1);
+        env->HI[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1);
     }
     RETURN();
 }
@@ -373,8 +373,8 @@ void op_div (void)
 void op_divu (void)
 {
     if (T1 != 0) {
-        env->LO = (int32_t)((uint32_t)T0 / (uint32_t)T1);
-        env->HI = (int32_t)((uint32_t)T0 % (uint32_t)T1);
+        env->LO[0][env->current_tc] = (int32_t)((uint32_t)T0 / (uint32_t)T1);
+        env->HI[0][env->current_tc] = (int32_t)((uint32_t)T0 % (uint32_t)T1);
     }
     RETURN();
 }
@@ -442,8 +442,8 @@ void op_ddivu (void)
 void op_ddivu (void)
 {
     if (T1 != 0) {
-        env->LO = T0 / T1;
-        env->HI = T0 % T1;
+        env->LO[0][env->current_tc] = T0 / T1;
+        env->HI[0][env->current_tc] = T0 % T1;
     }
     RETURN();
 }
@@ -814,13 +814,14 @@ void op_msubu (void)
 
 static inline uint64_t get_HILO (void)
 {
-    return ((uint64_t)env->HI << 32) | ((uint64_t)(uint32_t)env->LO);
+    return ((uint64_t)env->HI[0][env->current_tc] << 32) |
+            ((uint64_t)(uint32_t)env->LO[0][env->current_tc]);
 }
 
 static inline void set_HILO (uint64_t HILO)
 {
-    env->LO = (int32_t)(HILO & 0xFFFFFFFF);
-    env->HI = (int32_t)(HILO >> 32);
+    env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF);
+    env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
 }
 
 void op_mult (void)
@@ -875,13 +876,13 @@ void op_msubu (void)
 #ifdef TARGET_MIPS64
 void op_dmult (void)
 {
-    CALL_FROM_TB4(muls64, &(env->HI), &(env->LO), T0, T1);
+    CALL_FROM_TB4(muls64, &(env->HI[0][env->current_tc]), &(env->LO[0][env->current_tc]), T0, T1);
     RETURN();
 }
 
 void op_dmultu (void)
 {
-    CALL_FROM_TB4(mulu64, &(env->HI), &(env->LO), T0, T1);
+    CALL_FROM_TB4(mulu64, &(env->HI[0][env->current_tc]), &(env->LO[0][env->current_tc]), T0, T1);
     RETURN();
 }
 #endif
@@ -890,27 +891,27 @@ void op_dmultu (void)
 void op_movn (void)
 {
     if (T1 != 0)
-        env->gpr[PARAM1] = T0;
+        env->gpr[PARAM1][env->current_tc] = T0;
     RETURN();
 }
 
 void op_movz (void)
 {
     if (T1 == 0)
-        env->gpr[PARAM1] = T0;
+        env->gpr[PARAM1][env->current_tc] = T0;
     RETURN();
 }
 
 void op_movf (void)
 {
-    if (!(env->fcr31 & PARAM1))
+    if (!(env->fpu->fcr31 & PARAM1))
         T0 = T1;
     RETURN();
 }
 
 void op_movt (void)
 {
-    if (env->fcr31 & PARAM1)
+    if (env->fpu->fcr31 & PARAM1)
         T0 = T1;
     RETURN();
 }
@@ -966,7 +967,7 @@ void op_restore_breg_target (void)
 
 void op_breg (void)
 {
-    env->PC = T2;
+    env->PC[env->current_tc] = T2;
     RETURN();
 }
 
@@ -1017,18 +1018,176 @@ void op_mfc0_index (void)
     RETURN();
 }
 
+void op_mfc0_mvpcontrol (void)
+{
+    T0 = env->mvp->CP0_MVPControl;
+    RETURN();
+}
+
+void op_mfc0_mvpconf0 (void)
+{
+    T0 = env->mvp->CP0_MVPConf0;
+    RETURN();
+}
+
+void op_mfc0_mvpconf1 (void)
+{
+    T0 = env->mvp->CP0_MVPConf1;
+    RETURN();
+}
+
 void op_mfc0_random (void)
 {
     CALL_FROM_TB0(do_mfc0_random);
     RETURN();
 }
 
+void op_mfc0_vpecontrol (void)
+{
+    T0 = env->CP0_VPEControl;
+    RETURN();
+}
+
+void op_mfc0_vpeconf0 (void)
+{
+    T0 = env->CP0_VPEConf0;
+    RETURN();
+}
+
+void op_mfc0_vpeconf1 (void)
+{
+    T0 = env->CP0_VPEConf1;
+    RETURN();
+}
+
+void op_mfc0_yqmask (void)
+{
+    T0 = env->CP0_YQMask;
+    RETURN();
+}
+
+void op_mfc0_vpeschedule (void)
+{
+    T0 = env->CP0_VPESchedule;
+    RETURN();
+}
+
+void op_mfc0_vpeschefback (void)
+{
+    T0 = env->CP0_VPEScheFBack;
+    RETURN();
+}
+
+void op_mfc0_vpeopt (void)
+{
+    T0 = env->CP0_VPEOpt;
+    RETURN();
+}
+
 void op_mfc0_entrylo0 (void)
 {
     T0 = (int32_t)env->CP0_EntryLo0;
     RETURN();
 }
 
+void op_mfc0_tcstatus (void)
+{
+    T0 = env->CP0_TCStatus[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tcstatus(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->CP0_TCStatus[other_tc];
+    RETURN();
+}
+
+void op_mfc0_tcbind (void)
+{
+    T0 = env->CP0_TCBind[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tcbind(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->CP0_TCBind[other_tc];
+    RETURN();
+}
+
+void op_mfc0_tcrestart (void)
+{
+    T0 = env->PC[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tcrestart(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->PC[other_tc];
+    RETURN();
+}
+
+void op_mfc0_tchalt (void)
+{
+    T0 = env->CP0_TCHalt[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tchalt(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->CP0_TCHalt[other_tc];
+    RETURN();
+}
+
+void op_mfc0_tccontext (void)
+{
+    T0 = env->CP0_TCContext[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tccontext(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->CP0_TCContext[other_tc];
+    RETURN();
+}
+
+void op_mfc0_tcschedule (void)
+{
+    T0 = env->CP0_TCSchedule[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tcschedule(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->CP0_TCSchedule[other_tc];
+    RETURN();
+}
+
+void op_mfc0_tcschefback (void)
+{
+    T0 = env->CP0_TCScheFBack[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tcschefback(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->CP0_TCScheFBack[other_tc];
+    RETURN();
+}
+
 void op_mfc0_entrylo1 (void)
 {
     T0 = (int32_t)env->CP0_EntryLo1;
@@ -1059,6 +1218,36 @@ void op_mfc0_wired (void)
     RETURN();
 }
 
+void op_mfc0_srsconf0 (void)
+{
+    T0 = env->CP0_SRSConf0;
+    RETURN();
+}
+
+void op_mfc0_srsconf1 (void)
+{
+    T0 = env->CP0_SRSConf1;
+    RETURN();
+}
+
+void op_mfc0_srsconf2 (void)
+{
+    T0 = env->CP0_SRSConf2;
+    RETURN();
+}
+
+void op_mfc0_srsconf3 (void)
+{
+    T0 = env->CP0_SRSConf3;
+    RETURN();
+}
+
+void op_mfc0_srsconf4 (void)
+{
+    T0 = env->CP0_SRSConf4;
+    RETURN();
+}
+
 void op_mfc0_hwrena (void)
 {
     T0 = env->CP0_HWREna;
@@ -1083,6 +1272,14 @@ void op_mfc0_entryhi (void)
     RETURN();
 }
 
+void op_mftc0_entryhi(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = (env->CP0_EntryHi & ~0xff) | (env->CP0_TCStatus[other_tc] & 0xff);
+    RETURN();
+}
+
 void op_mfc0_compare (void)
 {
     T0 = env->CP0_Compare;
@@ -1095,6 +1292,18 @@ void op_mfc0_status (void)
     RETURN();
 }
 
+void op_mftc0_status(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    uint32_t tcstatus = env->CP0_TCStatus[other_tc];
+
+    T0 = env->CP0_Status & ~0xf1000018;
+    T0 |= tcstatus & (0xf << CP0TCSt_TCU0);
+    T0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX);
+    T0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_R0);
+    RETURN();
+}
+
 void op_mfc0_intctl (void)
 {
     T0 = env->CP0_IntCtl;
@@ -1211,6 +1420,17 @@ void op_mfc0_debug (void)
     RETURN();
 }
 
+void op_mftc0_debug(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    /* XXX: Might be wrong, check with EJTAG spec. */
+    T0 = (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
+         (env->CP0_Debug_tcstatus[other_tc] &
+          ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
+    RETURN();
+}
+
 void op_mfc0_depc (void)
 {
     T0 = (int32_t)env->CP0_DEPC;
@@ -1261,7 +1481,105 @@ void op_mfc0_desave (void)
 
 void op_mtc0_index (void)
 {
-    env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 % env->nb_tlb);
+    env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 % env->tlb->nb_tlb);
+    RETURN();
+}
+
+void op_mtc0_mvpcontrol (void)
+{
+    uint32_t mask = 0;
+    uint32_t newval;
+
+    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
+        mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
+                (1 << CP0MVPCo_EVP);
+    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
+        mask |= (1 << CP0MVPCo_STLB);
+    newval = (env->mvp->CP0_MVPControl & ~mask) | (T0 & mask);
+
+    // TODO: Enable/disable shared TLB, enable/disable VPEs.
+
+    env->mvp->CP0_MVPControl = newval;
+    RETURN();
+}
+
+void op_mtc0_vpecontrol (void)
+{
+    uint32_t mask;
+    uint32_t newval;
+
+    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
+           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
+    newval = (env->CP0_VPEControl & ~mask) | (T0 & mask);
+
+    /* Yield scheduler intercept not implemented. */
+    /* Gating storage scheduler intercept not implemented. */
+
+    // TODO: Enable/disable TCs.
+
+    env->CP0_VPEControl = newval;
+    RETURN();
+}
+
+void op_mtc0_vpeconf0 (void)
+{
+    uint32_t mask = 0;
+    uint32_t newval;
+
+    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
+        if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
+            mask |= (0xff << CP0VPEC0_XTC);
+        mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
+    }
+    newval = (env->CP0_VPEConf0 & ~mask) | (T0 & mask);
+
+    // TODO: TC exclusive handling due to ERL/EXL.
+
+    env->CP0_VPEConf0 = newval;
+    RETURN();
+}
+
+void op_mtc0_vpeconf1 (void)
+{
+    uint32_t mask = 0;
+    uint32_t newval;
+
+    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
+        mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
+                (0xff << CP0VPEC1_NCP1);
+    newval = (env->CP0_VPEConf1 & ~mask) | (T0 & mask);
+
+    /* UDI not implemented. */
+    /* CP2 not implemented. */
+
+    // TODO: Handle FPU (CP1) binding.
+
+    env->CP0_VPEConf1 = newval;
+    RETURN();
+}
+
+void op_mtc0_yqmask (void)
+{
+    /* Yield qualifier inputs not implemented. */
+    env->CP0_YQMask = 0x00000000;
+    RETURN();
+}
+
+void op_mtc0_vpeschedule (void)
+{
+    env->CP0_VPESchedule = T0;
+    RETURN();
+}
+
+void op_mtc0_vpeschefback (void)
+{
+    env->CP0_VPEScheFBack = T0;
+    RETURN();
+}
+
+void op_mtc0_vpeopt (void)
+{
+    env->CP0_VPEOpt = T0 & 0x0000ffff;
     RETURN();
 }
 
@@ -1273,6 +1591,135 @@ void op_mtc0_entrylo0 (void)
     RETURN();
 }
 
+void op_mtc0_tcstatus (void)
+{
+    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
+    uint32_t newval;
+
+    newval = (env->CP0_TCStatus[env->current_tc] & ~mask) | (T0 & mask);
+
+    // TODO: Sync with CP0_Status.
+
+    env->CP0_TCStatus[env->current_tc] = newval;
+    RETURN();
+}
+
+void op_mttc0_tcstatus (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    // TODO: Sync with CP0_Status.
+
+    env->CP0_TCStatus[other_tc] = T0;
+    RETURN();
+}
+
+void op_mtc0_tcbind (void)
+{
+    uint32_t mask = (1 << CP0TCBd_TBE);
+    uint32_t newval;
+
+    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;
+    RETURN();
+}
+
+void op_mttc0_tcbind (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    uint32_t mask = (1 << CP0TCBd_TBE);
+    uint32_t newval;
+
+    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;
+    RETURN();
+}
+
+void op_mtc0_tcrestart (void)
+{
+    env->PC[env->current_tc] = T0;
+    env->CP0_TCStatus[env->current_tc] &= ~(1 << CP0TCSt_TDS);
+    env->CP0_LLAddr = 0ULL;
+    /* MIPS16 not implemented. */
+    RETURN();
+}
+
+void op_mttc0_tcrestart (void)
+{
+    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. */
+    RETURN();
+}
+
+void op_mtc0_tchalt (void)
+{
+    env->CP0_TCHalt[env->current_tc] = T0 & 0x1;
+
+    // TODO: Halt TC / Restart (if allocated+active) TC.
+
+    RETURN();
+}
+
+void op_mttc0_tchalt (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    // TODO: Halt TC / Restart (if allocated+active) TC.
+
+    env->CP0_TCHalt[other_tc] = T0;
+    RETURN();
+}
+
+void op_mtc0_tccontext (void)
+{
+    env->CP0_TCContext[env->current_tc] = T0;
+    RETURN();
+}
+
+void op_mttc0_tccontext (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    env->CP0_TCContext[other_tc] = T0;
+    RETURN();
+}
+
+void op_mtc0_tcschedule (void)
+{
+    env->CP0_TCSchedule[env->current_tc] = T0;
+    RETURN();
+}
+
+void op_mttc0_tcschedule (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    env->CP0_TCSchedule[other_tc] = T0;
+    RETURN();
+}
+
+void op_mtc0_tcschefback (void)
+{
+    env->CP0_TCScheFBack[env->current_tc] = T0;
+    RETURN();
+}
+
+void op_mttc0_tcschefback (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    env->CP0_TCScheFBack[other_tc] = T0;
+    RETURN();
+}
+
 void op_mtc0_entrylo1 (void)
 {
     /* Large physaddr not implemented */
@@ -1305,7 +1752,37 @@ void op_mtc0_pagegrain (void)
 
 void op_mtc0_wired (void)
 {
-    env->CP0_Wired = T0 % env->nb_tlb;
+    env->CP0_Wired = T0 % env->tlb->nb_tlb;
+    RETURN();
+}
+
+void op_mtc0_srsconf0 (void)
+{
+    env->CP0_SRSConf0 |= T0 & env->CP0_SRSConf0_rw_bitmask;
+    RETURN();
+}
+
+void op_mtc0_srsconf1 (void)
+{
+    env->CP0_SRSConf1 |= T0 & env->CP0_SRSConf1_rw_bitmask;
+    RETURN();
+}
+
+void op_mtc0_srsconf2 (void)
+{
+    env->CP0_SRSConf2 |= T0 & env->CP0_SRSConf2_rw_bitmask;
+    RETURN();
+}
+
+void op_mtc0_srsconf3 (void)
+{
+    env->CP0_SRSConf3 |= T0 & env->CP0_SRSConf3_rw_bitmask;
+    RETURN();
+}
+
+void op_mtc0_srsconf4 (void)
+{
+    env->CP0_SRSConf4 |= T0 & env->CP0_SRSConf4_rw_bitmask;
     RETURN();
 }
 
@@ -1332,12 +1809,25 @@ void op_mtc0_entryhi (void)
 #endif
     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);
+    }
     /* If the ASID changes, flush qemu's TLB.  */
     if ((old & 0xFF) != (val & 0xFF))
         CALL_FROM_TB2(cpu_mips_tlb_flush, env, 1);
     RETURN();
 }
 
+void op_mttc0_entryhi(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (T0 & ~0xff);
+    env->CP0_TCStatus[other_tc] = (env->CP0_TCStatus[other_tc] & ~0xff) | (T0 & 0xff);
+    RETURN();
+}
+
 void op_mtc0_compare (void)
 {
     CALL_FROM_TB2(cpu_mips_store_compare, env, T0);
@@ -1347,9 +1837,8 @@ void op_mtc0_compare (void)
 void op_mtc0_status (void)
 {
     uint32_t val, old;
-    uint32_t mask = env->Status_rw_bitmask;
+    uint32_t mask = env->CP0_Status_rw_bitmask;
 
-    /* No reverse endianness, no MDMX/DSP implemented. */
     val = T0 & mask;
     old = env->CP0_Status;
     if (!(val & (1 << CP0St_EXL)) &&
@@ -1379,6 +1868,19 @@ void op_mtc0_status (void)
     RETURN();
 }
 
+void op_mttc0_status(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    uint32_t tcstatus = env->CP0_TCStatus[other_tc];
+
+    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_R0)) << (CP0TCSt_TKSU - CP0St_R0));
+    env->CP0_TCStatus[other_tc] = tcstatus;
+    RETURN();
+}
+
 void op_mtc0_intctl (void)
 {
     /* vectored interrupts not implemented, timer on int 7,
@@ -1389,15 +1891,14 @@ void op_mtc0_intctl (void)
 
 void op_mtc0_srsctl (void)
 {
-    /* shadow registers not implemented */
-    env->CP0_SRSCtl = 0;
+    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
+    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (T0 & mask);
     RETURN();
 }
 
 void op_mtc0_srsmap (void)
 {
-    /* shadow registers not implemented */
-    env->CP0_SRSMap = 0;
+    env->CP0_SRSMap = T0;
     RETURN();
 }
 
@@ -1460,6 +1961,13 @@ void op_mtc0_watchhi (void)
     RETURN();
 }
 
+void op_mtc0_xcontext (void)
+{
+    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
+    env->CP0_XContext = (env->CP0_XContext & mask) | (T0 & ~mask);
+    RETURN();
+}
+
 void op_mtc0_framemask (void)
 {
     env->CP0_Framemask = T0; /* XXX */
@@ -1476,6 +1984,17 @@ void op_mtc0_debug (void)
     RETURN();
 }
 
+void op_mttc0_debug(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    /* XXX: Might be wrong, check with EJTAG spec. */
+    env->CP0_Debug_tcstatus[other_tc] = T0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
+    env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
+                     (T0 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
+    RETURN();
+}
+
 void op_mtc0_depc (void)
 {
     env->CP0_DEPC = T0;
@@ -1525,10 +2044,21 @@ void op_mtc0_desave (void)
 }
 
 #ifdef TARGET_MIPS64
-void op_mtc0_xcontext (void)
+void op_dmfc0_yqmask (void)
 {
-    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
-    env->CP0_XContext = (env->CP0_XContext & mask) | (T0 & ~mask);
+    T0 = env->CP0_YQMask;
+    RETURN();
+}
+
+void op_dmfc0_vpeschedule (void)
+{
+    T0 = env->CP0_VPESchedule;
+    RETURN();
+}
+
+void op_dmfc0_vpeschefback (void)
+{
+    T0 = env->CP0_VPEScheFBack;
     RETURN();
 }
 
@@ -1538,6 +2068,36 @@ void op_dmfc0_entrylo0 (void)
     RETURN();
 }
 
+void op_dmfc0_tcrestart (void)
+{
+    T0 = env->PC[env->current_tc];
+    RETURN();
+}
+
+void op_dmfc0_tchalt (void)
+{
+    T0 = env->CP0_TCHalt[env->current_tc];
+    RETURN();
+}
+
+void op_dmfc0_tccontext (void)
+{
+    T0 = env->CP0_TCContext[env->current_tc];
+    RETURN();
+}
+
+void op_dmfc0_tcschedule (void)
+{
+    T0 = env->CP0_TCSchedule[env->current_tc];
+    RETURN();
+}
+
+void op_dmfc0_tcschefback (void)
+{
+    T0 = env->CP0_TCScheFBack[env->current_tc];
+    RETURN();
+}
+
 void op_dmfc0_entrylo1 (void)
 {
     T0 = env->CP0_EntryLo1;
@@ -1599,6 +2159,157 @@ void op_dmfc0_errorepc (void)
 }
 #endif /* TARGET_MIPS64 */
 
+/* MIPS MT functions */
+void op_mftgpr(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->gpr[PARAM1][other_tc];
+    RETURN();
+}
+
+void op_mftlo(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->LO[PARAM1][other_tc];
+    RETURN();
+}
+
+void op_mfthi(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->HI[PARAM1][other_tc];
+    RETURN();
+}
+
+void op_mftacx(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->ACX[PARAM1][other_tc];
+    RETURN();
+}
+
+void op_mftdsp(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->DSPControl[other_tc];
+    RETURN();
+}
+
+void op_mttgpr(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->gpr[PARAM1][other_tc];
+    RETURN();
+}
+
+void op_mttlo(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->LO[PARAM1][other_tc];
+    RETURN();
+}
+
+void op_mtthi(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->HI[PARAM1][other_tc];
+    RETURN();
+}
+
+void op_mttacx(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->ACX[PARAM1][other_tc];
+    RETURN();
+}
+
+void op_mttdsp(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->DSPControl[other_tc];
+    RETURN();
+}
+
+
+void op_dmt(void)
+{
+    // TODO
+    T0 = 0;
+    // rt = T0
+    RETURN();
+}
+
+void op_emt(void)
+{
+    // TODO
+    T0 = 0;
+    // rt = T0
+    RETURN();
+}
+
+void op_dvpe(void)
+{
+    // TODO
+    T0 = 0;
+    // rt = T0
+    RETURN();
+}
+
+void op_evpe(void)
+{
+    // TODO
+    T0 = 0;
+    // rt = T0
+    RETURN();
+}
+
+void op_fork(void)
+{
+    // T0 = rt, T1 = rs
+    T0 = 0;
+    // TODO: store to TC register
+    RETURN();
+}
+
+void op_yield(void)
+{
+    if (T0 < 0) {
+        /* No scheduling policy implemented. */
+        if (T0 != -2) {
+            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
+                env->CP0_TCStatus[env->current_tc] & (1 << CP0TCSt_DT)) {
+                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
+                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
+                CALL_FROM_TB1(do_raise_exception, EXCP_THREAD);
+            }
+        }
+    } else if (T0 == 0) {
+       if (0 /* TODO: TC underflow */) {
+            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
+            CALL_FROM_TB1(do_raise_exception, EXCP_THREAD);
+        } else {
+            // TODO: Deallocate TC
+        }
+    } else if (T0 > 0) {
+        /* Yield qualifier inputs not implemented. */
+        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
+        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
+        CALL_FROM_TB1(do_raise_exception, EXCP_THREAD);
+    }
+    T0 = env->CP0_YQMask;
+    RETURN();
+}
+
 /* CP1 functions */
 #if 0
 # define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env)
@@ -1617,30 +2328,14 @@ void op_cp0_enabled(void)
 
 void op_cfc1 (void)
 {
-    switch (T1) {
-    case 0:
-        T0 = (int32_t)env->fcr0;
-        break;
-    case 25:
-        T0 = ((env->fcr31 >> 24) & 0xfe) | ((env->fcr31 >> 23) & 0x1);
-        break;
-    case 26:
-        T0 = env->fcr31 & 0x0003f07c;
-        break;
-    case 28:
-        T0 = (env->fcr31 & 0x00000f83) | ((env->fcr31 >> 22) & 0x4);
-        break;
-    default:
-        T0 = (int32_t)env->fcr31;
-        break;
-    }
+    CALL_FROM_TB1(do_cfc1, PARAM1);
     DEBUG_FPU_STATE();
     RETURN();
 }
 
 void op_ctc1 (void)
 {
-    CALL_FROM_TB0(do_ctc1);
+    CALL_FROM_TB1(do_ctc1, PARAM1);
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -1842,21 +2537,21 @@ FLOAT_ROUNDOP(floor, w, s)
 
 FLOAT_OP(movf, d)
 {
-    if (!(env->fcr31 & PARAM1))
+    if (!(env->fpu->fcr31 & PARAM1))
         DT2 = DT0;
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(movf, s)
 {
-    if (!(env->fcr31 & PARAM1))
+    if (!(env->fpu->fcr31 & PARAM1))
         WT2 = WT0;
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(movf, ps)
 {
-    if (!(env->fcr31 & PARAM1)) {
+    if (!(env->fpu->fcr31 & PARAM1)) {
         WT2 = WT0;
         WTH2 = WTH0;
     }
@@ -1865,21 +2560,21 @@ FLOAT_OP(movf, ps)
 }
 FLOAT_OP(movt, d)
 {
-    if (env->fcr31 & PARAM1)
+    if (env->fpu->fcr31 & PARAM1)
         DT2 = DT0;
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(movt, s)
 {
-    if (env->fcr31 & PARAM1)
+    if (env->fpu->fcr31 & PARAM1)
         WT2 = WT0;
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(movt, ps)
 {
-    if (env->fcr31 & PARAM1) {
+    if (env->fpu->fcr31 & PARAM1) {
         WT2 = WT0;
         WTH2 = WTH0;
     }
@@ -1997,24 +2692,24 @@ FLOAT_HOP(mulr)
 #define FLOAT_TERNOP(name1, name2) \
 FLOAT_OP(name1 ## name2, d)        \
 {                                  \
-    FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status);    \
-    FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status);    \
+    FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status);    \
+    FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status);    \
     DEBUG_FPU_STATE();             \
     RETURN();                      \
 }                                  \
 FLOAT_OP(name1 ## name2, s)        \
 {                                  \
-    FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status);    \
-    FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status);    \
+    FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status);    \
+    FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status);    \
     DEBUG_FPU_STATE();             \
     RETURN();                      \
 }                                  \
 FLOAT_OP(name1 ## name2, ps)       \
 {                                  \
-    FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status);    \
-    FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fp_status); \
-    FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status);    \
-    FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \
+    FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status);    \
+    FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \
+    FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status);    \
+    FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \
     DEBUG_FPU_STATE();             \
     RETURN();                      \
 }
@@ -2026,26 +2721,26 @@ FLOAT_TERNOP(mul, sub)
 #define FLOAT_NTERNOP(name1, name2) \
 FLOAT_OP(n ## name1 ## name2, d)    \
 {                                   \
-    FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status);    \
-    FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status);    \
+    FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status);    \
+    FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status);    \
     FDT2 ^= 1ULL << 63;             \
     DEBUG_FPU_STATE();              \
     RETURN();                       \
 }                                   \
 FLOAT_OP(n ## name1 ## name2, s)    \
 {                                   \
-    FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status);    \
-    FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status);    \
+    FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status);    \
+    FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status);    \
     FST2 ^= 1 << 31;                \
     DEBUG_FPU_STATE();              \
     RETURN();                       \
 }                                   \
 FLOAT_OP(n ## name1 ## name2, ps)   \
 {                                   \
-    FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status);    \
-    FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fp_status); \
-    FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status);    \
-    FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \
+    FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status);    \
+    FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \
+    FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status);    \
+    FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \
     FST2 ^= 1 << 31;                \
     FSTH2 ^= 1 << 31;               \
     DEBUG_FPU_STATE();              \
@@ -2059,13 +2754,13 @@ FLOAT_NTERNOP(mul, sub)
 #define FLOAT_UNOP(name)  \
 FLOAT_OP(name, d)         \
 {                         \
-    FDT2 = float64_ ## name(FDT0, &env->fp_status);   \
+    FDT2 = float64_ ## name(FDT0, &env->fpu->fp_status);   \
     DEBUG_FPU_STATE();    \
     RETURN();                      \
 }                         \
 FLOAT_OP(name, s)         \
 {                         \
-    FST2 = float32_ ## name(FST0, &env->fp_status);   \
+    FST2 = float32_ ## name(FST0, &env->fpu->fp_status);   \
     DEBUG_FPU_STATE();    \
     RETURN();             \
 }
@@ -2141,9 +2836,9 @@ FLOAT_OP(alnv, ps)
 
 #ifdef CONFIG_SOFTFLOAT
 #define clear_invalid() do {                                \
-    int flags = get_float_exception_flags(&env->fp_status); \
+    int flags = get_float_exception_flags(&env->fpu->fp_status); \
     flags &= ~float_flag_invalid;                           \
-    set_float_exception_flags(flags, &env->fp_status);      \
+    set_float_exception_flags(flags, &env->fpu->fp_status);      \
 } while(0)
 #else
 #define clear_invalid() do { } while(0)
@@ -2190,63 +2885,63 @@ CMP_OPS(ngt)
 
 void op_bc1f (void)
 {
-    T0 = !!(~GET_FP_COND(env) & (0x1 << PARAM1));
+    T0 = !!(~GET_FP_COND(env->fpu) & (0x1 << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
 void op_bc1any2f (void)
 {
-    T0 = !!(~GET_FP_COND(env) & (0x3 << PARAM1));
+    T0 = !!(~GET_FP_COND(env->fpu) & (0x3 << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
 void op_bc1any4f (void)
 {
-    T0 = !!(~GET_FP_COND(env) & (0xf << PARAM1));
+    T0 = !!(~GET_FP_COND(env->fpu) & (0xf << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
 
 void op_bc1t (void)
 {
-    T0 = !!(GET_FP_COND(env) & (0x1 << PARAM1));
+    T0 = !!(GET_FP_COND(env->fpu) & (0x1 << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
 void op_bc1any2t (void)
 {
-    T0 = !!(GET_FP_COND(env) & (0x3 << PARAM1));
+    T0 = !!(GET_FP_COND(env->fpu) & (0x3 << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
 void op_bc1any4t (void)
 {
-    T0 = !!(GET_FP_COND(env) & (0xf << PARAM1));
+    T0 = !!(GET_FP_COND(env->fpu) & (0xf << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
 
 void op_tlbwi (void)
 {
-    CALL_FROM_TB0(env->do_tlbwi);
+    CALL_FROM_TB0(env->tlb->do_tlbwi);
     RETURN();
 }
 
 void op_tlbwr (void)
 {
-    CALL_FROM_TB0(env->do_tlbwr);
+    CALL_FROM_TB0(env->tlb->do_tlbwr);
     RETURN();
 }
 
 void op_tlbp (void)
 {
-    CALL_FROM_TB0(env->do_tlbp);
+    CALL_FROM_TB0(env->tlb->do_tlbp);
     RETURN();
 }
 
 void op_tlbr (void)
 {
-    CALL_FROM_TB0(env->do_tlbr);
+    CALL_FROM_TB0(env->tlb->do_tlbr);
     RETURN();
 }
 
@@ -2307,10 +3002,10 @@ void op_eret (void)
     if (loglevel & CPU_LOG_EXEC)
         CALL_FROM_TB0(debug_pre_eret);
     if (env->CP0_Status & (1 << CP0St_ERL)) {
-        env->PC = env->CP0_ErrorEPC;
+        env->PC[env->current_tc] = env->CP0_ErrorEPC;
         env->CP0_Status &= ~(1 << CP0St_ERL);
     } else {
-        env->PC = env->CP0_EPC;
+        env->PC[env->current_tc] = env->CP0_EPC;
         env->CP0_Status &= ~(1 << CP0St_EXL);
     }
     if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
@@ -2335,7 +3030,7 @@ void op_deret (void)
 {
     if (loglevel & CPU_LOG_EXEC)
         CALL_FROM_TB0(debug_pre_eret);
-    env->PC = env->CP0_DEPC;
+    env->PC[env->current_tc] = env->CP0_DEPC;
     env->hflags |= MIPS_HFLAG_DM;
     if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
         !(env->CP0_Status & (1 << CP0St_ERL)) &&
@@ -2407,14 +3102,14 @@ void op_save_state (void)
 
 void op_save_pc (void)
 {
-    env->PC = PARAM1;
+    env->PC[env->current_tc] = PARAM1;
     RETURN();
 }
 
 #ifdef TARGET_MIPS64
 void op_save_pc64 (void)
 {
-    env->PC = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2;
+    env->PC[env->current_tc] = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2;
     RETURN();
 }
 #endif
index 477b80d516e5720ae4763b3ea24fbc2e53702598..c87317a44f04100991315c1e643ebddfe7ccfe05 100644 (file)
@@ -160,13 +160,13 @@ void do_drotrv (void)
 #if TARGET_LONG_BITS > HOST_LONG_BITS
 static inline uint64_t get_HILO (void)
 {
-    return (env->HI << 32) | (uint32_t)env->LO;
+    return (env->HI[0][env->current_tc] << 32) | (uint32_t)env->LO[0][env->current_tc];
 }
 
 static inline void set_HILO (uint64_t HILO)
 {
-    env->LO = (int32_t)HILO;
-    env->HI = (int32_t)(HILO >> 32);
+    env->LO[0][env->current_tc] = (int32_t)HILO;
+    env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
 }
 
 void do_mult (void)
@@ -217,8 +217,8 @@ void do_div (void)
 {
     /* 64bit datatypes because we may see overflow/underflow. */
     if (T1 != 0) {
-        env->LO = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1);
-        env->HI = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1);
+        env->LO[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1);
+        env->HI[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1);
     }
 }
 #endif
@@ -228,8 +228,8 @@ void do_ddiv (void)
 {
     if (T1 != 0) {
         lldiv_t res = lldiv((int64_t)T0, (int64_t)T1);
-        env->LO = res.quot;
-        env->HI = res.rem;
+        env->LO[0][env->current_tc] = res.quot;
+        env->HI[0][env->current_tc] = res.rem;
     }
 }
 
@@ -237,8 +237,8 @@ void do_ddiv (void)
 void do_ddivu (void)
 {
     if (T1 != 0) {
-        env->LO = T0 / T1;
-        env->HI = T0 % T1;
+        env->LO[0][env->current_tc] = T0 / T1;
+        env->HI[0][env->current_tc] = T0 % T1;
     }
 }
 #endif
@@ -316,10 +316,10 @@ void do_mtc0_status_irqraise_debug(void)
 void fpu_handle_exception(void)
 {
 #ifdef CONFIG_SOFTFLOAT
-    int flags = get_float_exception_flags(&env->fp_status);
+    int flags = get_float_exception_flags(&env->fpu->fp_status);
     unsigned int cpuflags = 0, enable, cause = 0;
 
-    enable = GET_FP_ENABLE(env->fcr31);
+    enable = GET_FP_ENABLE(env->fpu->fcr31);
 
     /* determine current flags */   
     if (flags & float_flag_invalid) {
@@ -342,11 +342,11 @@ void fpu_handle_exception(void)
         cpuflags |= FP_INEXACT; 
         cause |= FP_INEXACT & enable;
     }
-    SET_FP_FLAGS(env->fcr31, cpuflags);
-    SET_FP_CAUSE(env->fcr31, cause);
+    SET_FP_FLAGS(env->fpu->fcr31, cpuflags);
+    SET_FP_CAUSE(env->fpu->fcr31, cause);
 #else
-    SET_FP_FLAGS(env->fcr31, 0);
-    SET_FP_CAUSE(env->fcr31, 0);
+    SET_FP_FLAGS(env->fpu->fcr31, 0);
+    SET_FP_CAUSE(env->fpu->fcr31, 0);
 #endif
 }
 
@@ -355,14 +355,14 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global)
 {
     /* Flush qemu's TLB and discard all shadowed entries.  */
     tlb_flush (env, flush_global);
-    env->tlb_in_use = env->nb_tlb;
+    env->tlb->tlb_in_use = env->tlb->nb_tlb;
 }
 
 static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
 {
     /* Discard entries from env->tlb[first] onwards.  */
-    while (env->tlb_in_use > first) {
-        r4k_invalidate_tlb(env, --env->tlb_in_use, 0);
+    while (env->tlb->tlb_in_use > first) {
+        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
     }
 }
 
@@ -371,7 +371,7 @@ static void r4k_fill_tlb (int idx)
     r4k_tlb_t *tlb;
 
     /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
-    tlb = &env->mmu.r4k.tlb[idx];
+    tlb = &env->tlb->mmu.r4k.tlb[idx];
     tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
 #ifdef TARGET_MIPS64
     tlb->VPN &= env->SEGMask;
@@ -394,10 +394,10 @@ void r4k_do_tlbwi (void)
     /* Discard cached TLB entries.  We could avoid doing this if the
        tlbwi is just upgrading access permissions on the current entry;
        that might be a further win.  */
-    r4k_mips_tlb_flush_extra (env, env->nb_tlb);
+    r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
 
-    r4k_invalidate_tlb(env, env->CP0_Index % env->nb_tlb, 0);
-    r4k_fill_tlb(env->CP0_Index % env->nb_tlb);
+    r4k_invalidate_tlb(env, env->CP0_Index % env->tlb->nb_tlb, 0);
+    r4k_fill_tlb(env->CP0_Index % env->tlb->nb_tlb);
 }
 
 void r4k_do_tlbwr (void)
@@ -418,8 +418,8 @@ void r4k_do_tlbp (void)
     int i;
 
     ASID = env->CP0_EntryHi & 0xFF;
-    for (i = 0; i < env->nb_tlb; i++) {
-        tlb = &env->mmu.r4k.tlb[i];
+    for (i = 0; i < env->tlb->nb_tlb; i++) {
+        tlb = &env->tlb->mmu.r4k.tlb[i];
         /* 1k pages are not supported. */
         mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
         tag = env->CP0_EntryHi & ~mask;
@@ -431,10 +431,10 @@ void r4k_do_tlbp (void)
             break;
         }
     }
-    if (i == env->nb_tlb) {
+    if (i == env->tlb->nb_tlb) {
         /* No match.  Discard any shadow entries, if any of them match.  */
-        for (i = env->nb_tlb; i < env->tlb_in_use; i++) {
-           tlb = &env->mmu.r4k.tlb[i];
+        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
+           tlb = &env->tlb->mmu.r4k.tlb[i];
            /* 1k pages are not supported. */
            mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
            tag = env->CP0_EntryHi & ~mask;
@@ -456,13 +456,13 @@ void r4k_do_tlbr (void)
     uint8_t ASID;
 
     ASID = env->CP0_EntryHi & 0xFF;
-    tlb = &env->mmu.r4k.tlb[env->CP0_Index % env->nb_tlb];
+    tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb];
 
     /* If this will change the current ASID, flush qemu's TLB.  */
     if (ASID != tlb->ASID)
         cpu_mips_tlb_flush (env, 1);
 
-    r4k_mips_tlb_flush_extra(env, env->nb_tlb);
+    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
 
     env->CP0_EntryHi = tlb->VPN | tlb->ASID;
     env->CP0_PageMask = tlb->PageMask;
@@ -491,7 +491,7 @@ void dump_sc (void)
 void debug_pre_eret (void)
 {
     fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
-            env->PC, env->CP0_EPC);
+            env->PC[env->current_tc], 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)
@@ -502,7 +502,7 @@ void debug_pre_eret (void)
 void debug_post_eret (void)
 {
     fprintf(logfile, "  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
-            env->PC, env->CP0_EPC);
+            env->PC[env->current_tc], 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)
@@ -518,21 +518,21 @@ void do_pmon (int function)
     function /= 2;
     switch (function) {
     case 2: /* TODO: char inbyte(int waitflag); */
-        if (env->gpr[4] == 0)
-            env->gpr[2] = -1;
+        if (env->gpr[4][env->current_tc] == 0)
+            env->gpr[2][env->current_tc] = -1;
         /* Fall through */
     case 11: /* TODO: char inbyte (void); */
-        env->gpr[2] = -1;
+        env->gpr[2][env->current_tc] = -1;
         break;
     case 3:
     case 12:
-        printf("%c", (char)(env->gpr[4] & 0xFF));
+        printf("%c", (char)(env->gpr[4][env->current_tc] & 0xFF));
         break;
     case 17:
         break;
     case 158:
         {
-            unsigned char *fmt = (void *)(unsigned long)env->gpr[4];
+            unsigned char *fmt = (void *)(unsigned long)env->gpr[4][env->current_tc];
             printf("%s", fmt);
         }
         break;
@@ -613,40 +613,61 @@ unsigned int ieee_rm[] = {
 };
 
 #define RESTORE_ROUNDING_MODE \
-    set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
+    set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status)
 
-void do_ctc1 (void)
+void do_cfc1 (int reg)
 {
-    switch(T1) {
+    switch (reg) {
+    case 0:
+        T0 = (int32_t)env->fpu->fcr0;
+        break;
+    case 25:
+        T0 = ((env->fpu->fcr31 >> 24) & 0xfe) | ((env->fpu->fcr31 >> 23) & 0x1);
+        break;
+    case 26:
+        T0 = env->fpu->fcr31 & 0x0003f07c;
+        break;
+    case 28:
+        T0 = (env->fpu->fcr31 & 0x00000f83) | ((env->fpu->fcr31 >> 22) & 0x4);
+        break;
+    default:
+        T0 = (int32_t)env->fpu->fcr31;
+        break;
+    }
+}
+
+void do_ctc1 (int reg)
+{
+    switch(reg) {
     case 25:
         if (T0 & 0xffffff00)
             return;
-        env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) |
+        env->fpu->fcr31 = (env->fpu->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) |
                      ((T0 & 0x1) << 23);
         break;
     case 26:
         if (T0 & 0x007c0000)
             return;
-        env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c);
+        env->fpu->fcr31 = (env->fpu->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c);
         break;
     case 28:
         if (T0 & 0x007c0000)
             return;
-        env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) |
+        env->fpu->fcr31 = (env->fpu->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) |
                      ((T0 & 0x4) << 22);
         break;
     case 31:
         if (T0 & 0x007c0000)
             return;
-        env->fcr31 = T0;
+        env->fpu->fcr31 = T0;
         break;
     default:
         return;
     }
     /* set rounding mode */
     RESTORE_ROUNDING_MODE;
-    set_float_exception_flags(0, &env->fp_status);
-    if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31))
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    if ((GET_FP_ENABLE(env->fpu->fcr31) | 0x20) & GET_FP_CAUSE(env->fpu->fcr31))
         do_raise_exception(EXCP_FPE);
 }
 
@@ -670,325 +691,325 @@ inline char mips_ex_to_ieee(char xcpt)
 
 inline void update_fcr31(void)
 {
-    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status));
+    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fpu->fp_status));
 
-    SET_FP_CAUSE(env->fcr31, tmp);
-    if (GET_FP_ENABLE(env->fcr31) & tmp)
+    SET_FP_CAUSE(env->fpu->fcr31, tmp);
+    if (GET_FP_ENABLE(env->fpu->fcr31) & tmp)
         do_raise_exception(EXCP_FPE);
     else
-        UPDATE_FP_FLAGS(env->fcr31, tmp);
+        UPDATE_FP_FLAGS(env->fpu->fcr31, tmp);
 }
 
 #define FLOAT_OP(name, p) void do_float_##name##_##p(void)
 
 FLOAT_OP(cvtd, s)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FDT2 = float32_to_float64(FST0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float32_to_float64(FST0, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(cvtd, w)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FDT2 = int32_to_float64(WT0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = int32_to_float64(WT0, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(cvtd, l)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FDT2 = int64_to_float64(DT0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = int64_to_float64(DT0, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(cvtl, d)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    DT2 = float64_to_int64(FDT0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         DT2 = 0x7fffffffffffffffULL;
 }
 FLOAT_OP(cvtl, s)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    DT2 = float32_to_int64(FST0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         DT2 = 0x7fffffffffffffffULL;
 }
 
 FLOAT_OP(cvtps, pw)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = int32_to_float32(WT0, &env->fp_status);
-    FSTH2 = int32_to_float32(WTH0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
+    FSTH2 = int32_to_float32(WTH0, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(cvtpw, ps)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    WT2 = float32_to_int32(FST0, &env->fp_status);
-    WTH2 = float32_to_int32(FSTH0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
+    WTH2 = float32_to_int32(FSTH0, &env->fpu->fp_status);
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         WT2 = 0x7fffffff;
 }
 FLOAT_OP(cvts, d)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float64_to_float32(FDT0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float64_to_float32(FDT0, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(cvts, w)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = int32_to_float32(WT0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(cvts, l)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = int64_to_float32(DT0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = int64_to_float32(DT0, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(cvts, pl)
 {
-    set_float_exception_flags(0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
     WT2 = WT0;
     update_fcr31();
 }
 FLOAT_OP(cvts, pu)
 {
-    set_float_exception_flags(0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
     WT2 = WTH0;
     update_fcr31();
 }
 FLOAT_OP(cvtw, s)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    WT2 = float32_to_int32(FST0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         WT2 = 0x7fffffff;
 }
 FLOAT_OP(cvtw, d)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    WT2 = float64_to_int32(FDT0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         WT2 = 0x7fffffff;
 }
 
 FLOAT_OP(roundl, d)
 {
-    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
-    DT2 = float64_to_int64(FDT0, &env->fp_status);
+    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
+    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
     RESTORE_ROUNDING_MODE;
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         DT2 = 0x7fffffffffffffffULL;
 }
 FLOAT_OP(roundl, s)
 {
-    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
-    DT2 = float32_to_int64(FST0, &env->fp_status);
+    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
+    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
     RESTORE_ROUNDING_MODE;
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         DT2 = 0x7fffffffffffffffULL;
 }
 FLOAT_OP(roundw, d)
 {
-    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
-    WT2 = float64_to_int32(FDT0, &env->fp_status);
+    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
+    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
     RESTORE_ROUNDING_MODE;
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         WT2 = 0x7fffffff;
 }
 FLOAT_OP(roundw, s)
 {
-    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
-    WT2 = float32_to_int32(FST0, &env->fp_status);
+    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
+    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
     RESTORE_ROUNDING_MODE;
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         WT2 = 0x7fffffff;
 }
 
 FLOAT_OP(truncl, d)
 {
-    DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status);
+    DT2 = float64_to_int64_round_to_zero(FDT0, &env->fpu->fp_status);
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         DT2 = 0x7fffffffffffffffULL;
 }
 FLOAT_OP(truncl, s)
 {
-    DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status);
+    DT2 = float32_to_int64_round_to_zero(FST0, &env->fpu->fp_status);
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         DT2 = 0x7fffffffffffffffULL;
 }
 FLOAT_OP(truncw, d)
 {
-    WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status);
+    WT2 = float64_to_int32_round_to_zero(FDT0, &env->fpu->fp_status);
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         WT2 = 0x7fffffff;
 }
 FLOAT_OP(truncw, s)
 {
-    WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status);
+    WT2 = float32_to_int32_round_to_zero(FST0, &env->fpu->fp_status);
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         WT2 = 0x7fffffff;
 }
 
 FLOAT_OP(ceill, d)
 {
-    set_float_rounding_mode(float_round_up, &env->fp_status);
-    DT2 = float64_to_int64(FDT0, &env->fp_status);
+    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
+    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
     RESTORE_ROUNDING_MODE;
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         DT2 = 0x7fffffffffffffffULL;
 }
 FLOAT_OP(ceill, s)
 {
-    set_float_rounding_mode(float_round_up, &env->fp_status);
-    DT2 = float32_to_int64(FST0, &env->fp_status);
+    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
+    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
     RESTORE_ROUNDING_MODE;
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         DT2 = 0x7fffffffffffffffULL;
 }
 FLOAT_OP(ceilw, d)
 {
-    set_float_rounding_mode(float_round_up, &env->fp_status);
-    WT2 = float64_to_int32(FDT0, &env->fp_status);
+    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
+    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
     RESTORE_ROUNDING_MODE;
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         WT2 = 0x7fffffff;
 }
 FLOAT_OP(ceilw, s)
 {
-    set_float_rounding_mode(float_round_up, &env->fp_status);
-    WT2 = float32_to_int32(FST0, &env->fp_status);
+    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
+    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
     RESTORE_ROUNDING_MODE;
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         WT2 = 0x7fffffff;
 }
 
 FLOAT_OP(floorl, d)
 {
-    set_float_rounding_mode(float_round_down, &env->fp_status);
-    DT2 = float64_to_int64(FDT0, &env->fp_status);
+    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
+    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
     RESTORE_ROUNDING_MODE;
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         DT2 = 0x7fffffffffffffffULL;
 }
 FLOAT_OP(floorl, s)
 {
-    set_float_rounding_mode(float_round_down, &env->fp_status);
-    DT2 = float32_to_int64(FST0, &env->fp_status);
+    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
+    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
     RESTORE_ROUNDING_MODE;
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         DT2 = 0x7fffffffffffffffULL;
 }
 FLOAT_OP(floorw, d)
 {
-    set_float_rounding_mode(float_round_down, &env->fp_status);
-    WT2 = float64_to_int32(FDT0, &env->fp_status);
+    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
+    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
     RESTORE_ROUNDING_MODE;
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         WT2 = 0x7fffffff;
 }
 FLOAT_OP(floorw, s)
 {
-    set_float_rounding_mode(float_round_down, &env->fp_status);
-    WT2 = float32_to_int32(FST0, &env->fp_status);
+    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
+    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
     RESTORE_ROUNDING_MODE;
     update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
         WT2 = 0x7fffffff;
 }
 
 /* MIPS specific unary operations */
 FLOAT_OP(recip, d)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(recip, s)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
     update_fcr31();
 }
 
 FLOAT_OP(rsqrt, d)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FDT2 = float64_sqrt(FDT0, &env->fp_status);
-    FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
+    FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(rsqrt, s)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_sqrt(FST0, &env->fp_status);
-    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
     update_fcr31();
 }
 
 FLOAT_OP(recip1, d)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(recip1, s)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(recip1, ps)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status);
-    FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
+    FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fpu->fp_status);
     update_fcr31();
 }
 
 FLOAT_OP(rsqrt1, d)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FDT2 = float64_sqrt(FDT0, &env->fp_status);
-    FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
+    FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(rsqrt1, s)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_sqrt(FST0, &env->fp_status);
-    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
     update_fcr31();
 }
 FLOAT_OP(rsqrt1, ps)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_sqrt(FST0, &env->fp_status);
-    FSTH2 = float32_sqrt(FSTH0, &env->fp_status);
-    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status);
-    FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
+    FSTH2 = float32_sqrt(FSTH0, &env->fpu->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
+    FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fpu->fp_status);
     update_fcr31();
 }
 
@@ -996,41 +1017,41 @@ FLOAT_OP(rsqrt1, ps)
 #define FLOAT_BINOP(name) \
 FLOAT_OP(name, d)         \
 {                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-    FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);    \
-    update_fcr31();                                           \
-    if (GET_FP_CAUSE(env->fcr31) & FP_INVALID)                \
-        FDT2 = 0x7ff7ffffffffffffULL;                         \
-    else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {       \
-        if ((env->fcr31 & 0x3) == 0)                          \
-            FDT2 &= FLOAT_SIGN64;                             \
+    set_float_exception_flags(0, &env->fpu->fp_status);            \
+    FDT2 = float64_ ## name (FDT0, FDT1, &env->fpu->fp_status);    \
+    update_fcr31();                                                \
+    if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID)                \
+        FDT2 = 0x7ff7ffffffffffffULL;                              \
+    else if (GET_FP_CAUSE(env->fpu->fcr31) & FP_UNDERFLOW) {       \
+        if ((env->fpu->fcr31 & 0x3) == 0)                          \
+            FDT2 &= FLOAT_SIGN64;                                  \
     }                     \
 }                         \
 FLOAT_OP(name, s)         \
 {                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
-    update_fcr31();                                           \
-    if (GET_FP_CAUSE(env->fcr31) & FP_INVALID)                \
-        FST2 = 0x7fbfffff;                                    \
-    else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {       \
-        if ((env->fcr31 & 0x3) == 0)                          \
-            FST2 &= FLOAT_SIGN32;                             \
+    set_float_exception_flags(0, &env->fpu->fp_status);            \
+    FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status);    \
+    update_fcr31();                                                \
+    if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID)                \
+        FST2 = 0x7fbfffff;                                         \
+    else if (GET_FP_CAUSE(env->fpu->fcr31) & FP_UNDERFLOW) {       \
+        if ((env->fpu->fcr31 & 0x3) == 0)                          \
+            FST2 &= FLOAT_SIGN32;                                  \
     }                     \
 }                         \
 FLOAT_OP(name, ps)        \
 {                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
-    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \
+    set_float_exception_flags(0, &env->fpu->fp_status);            \
+    FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status);    \
+    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fpu->fp_status); \
     update_fcr31();       \
-    if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) {              \
-        FST2 = 0x7fbfffff;                                    \
-        FSTH2 = 0x7fbfffff;                                   \
-    } else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {     \
-        if ((env->fcr31 & 0x3) == 0) {                        \
-            FST2 &= FLOAT_SIGN32;                             \
-            FSTH2 &= FLOAT_SIGN32;                            \
+    if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) {              \
+        FST2 = 0x7fbfffff;                                         \
+        FSTH2 = 0x7fbfffff;                                        \
+    } else if (GET_FP_CAUSE(env->fpu->fcr31) & FP_UNDERFLOW) {     \
+        if ((env->fpu->fcr31 & 0x3) == 0) {                        \
+            FST2 &= FLOAT_SIGN32;                                  \
+            FSTH2 &= FLOAT_SIGN32;                                 \
         }                 \
     }                     \
 }
@@ -1043,69 +1064,69 @@ FLOAT_BINOP(div)
 /* MIPS specific binary operations */
 FLOAT_OP(recip2, d)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FDT2 = float64_mul(FDT0, FDT2, &env->fp_status);
-    FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fp_status) ^ FLOAT_SIGN64;
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
+    FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status) ^ FLOAT_SIGN64;
     update_fcr31();
 }
 FLOAT_OP(recip2, s)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_mul(FST0, FST2, &env->fp_status);
-    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32;
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
+    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
     update_fcr31();
 }
 FLOAT_OP(recip2, ps)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_mul(FST0, FST2, &env->fp_status);
-    FSTH2 = float32_mul(FSTH0, FSTH2, &env->fp_status);
-    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32;
-    FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32;
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
+    FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
+    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
+    FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
     update_fcr31();
 }
 
 FLOAT_OP(rsqrt2, d)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FDT2 = float64_mul(FDT0, FDT2, &env->fp_status);
-    FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fp_status);
-    FDT2 = float64_div(FDT2, FLOAT_TWO64, &env->fp_status) ^ FLOAT_SIGN64;
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
+    FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status);
+    FDT2 = float64_div(FDT2, FLOAT_TWO64, &env->fpu->fp_status) ^ FLOAT_SIGN64;
     update_fcr31();
 }
 FLOAT_OP(rsqrt2, s)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_mul(FST0, FST2, &env->fp_status);
-    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status);
-    FST2 = float32_div(FST2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32;
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
+    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
+    FST2 = float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
     update_fcr31();
 }
 FLOAT_OP(rsqrt2, ps)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_mul(FST0, FST2, &env->fp_status);
-    FSTH2 = float32_mul(FSTH0, FSTH2, &env->fp_status);
-    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status);
-    FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fp_status);
-    FST2 = float32_div(FST2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32;
-    FSTH2 = float32_div(FSTH2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32;
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
+    FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
+    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
+    FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status);
+    FST2 = float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
+    FSTH2 = float32_div(FSTH2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
     update_fcr31();
 }
 
 FLOAT_OP(addr, ps)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_add (FST0, FSTH0, &env->fp_status);
-    FSTH2 = float32_add (FST1, FSTH1, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_add (FST0, FSTH0, &env->fpu->fp_status);
+    FSTH2 = float32_add (FST1, FSTH1, &env->fpu->fp_status);
     update_fcr31();
 }
 
 FLOAT_OP(mulr, ps)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_mul (FST0, FSTH0, &env->fp_status);
-    FSTH2 = float32_mul (FST1, FSTH1, &env->fp_status);
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_mul (FST0, FSTH0, &env->fpu->fp_status);
+    FSTH2 = float32_mul (FST1, FSTH1, &env->fpu->fp_status);
     update_fcr31();
 }
 
@@ -1116,9 +1137,9 @@ void do_cmp_d_ ## op (long cc)                 \
     int c = cond;                              \
     update_fcr31();                            \
     if (c)                                     \
-        SET_FP_COND(cc, env);                  \
+        SET_FP_COND(cc, env->fpu);             \
     else                                       \
-        CLEAR_FP_COND(cc, env);                \
+        CLEAR_FP_COND(cc, env->fpu);           \
 }                                              \
 void do_cmpabs_d_ ## op (long cc)              \
 {                                              \
@@ -1128,9 +1149,9 @@ void do_cmpabs_d_ ## op (long cc)              \
     c = cond;                                  \
     update_fcr31();                            \
     if (c)                                     \
-        SET_FP_COND(cc, env);                  \
+        SET_FP_COND(cc, env->fpu);             \
     else                                       \
-        CLEAR_FP_COND(cc, env);                \
+        CLEAR_FP_COND(cc, env->fpu);           \
 }
 
 int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
@@ -1149,24 +1170,24 @@ int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
 
 /* NOTE: the comma operator will make "cond" to eval to false,
  * but float*_is_unordered() is still called. */
-FOP_COND_D(f,   (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0))
-FOP_COND_D(un,  float64_is_unordered(0, FDT1, FDT0, &env->fp_status))
-FOP_COND_D(eq,  !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_le(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(f,   (float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status), 0))
+FOP_COND_D(un,  float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status))
+FOP_COND_D(eq,  !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_le(FDT0, FDT1, &env->fpu->fp_status))
 /* NOTE: the comma operator will make "cond" to eval to false,
  * but float*_is_unordered() is still called. */
-FOP_COND_D(sf,  (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0))
-FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status))
-FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(lt,  !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(le,  !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_le(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(sf,  (float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status), 0))
+FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status))
+FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(lt,  !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(le,  !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_le(FDT0, FDT1, &env->fpu->fp_status))
 
 #define FOP_COND_S(op, cond)                   \
 void do_cmp_s_ ## op (long cc)                 \
@@ -1174,9 +1195,9 @@ void do_cmp_s_ ## op (long cc)                 \
     int c = cond;                              \
     update_fcr31();                            \
     if (c)                                     \
-        SET_FP_COND(cc, env);                  \
+        SET_FP_COND(cc, env->fpu);             \
     else                                       \
-        CLEAR_FP_COND(cc, env);                \
+        CLEAR_FP_COND(cc, env->fpu);           \
 }                                              \
 void do_cmpabs_s_ ## op (long cc)              \
 {                                              \
@@ -1186,9 +1207,9 @@ void do_cmpabs_s_ ## op (long cc)              \
     c = cond;                                  \
     update_fcr31();                            \
     if (c)                                     \
-        SET_FP_COND(cc, env);                  \
+        SET_FP_COND(cc, env->fpu);             \
     else                                       \
-        CLEAR_FP_COND(cc, env);                \
+        CLEAR_FP_COND(cc, env->fpu);           \
 }
 
 flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
@@ -1207,24 +1228,24 @@ flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
 
 /* NOTE: the comma operator will make "cond" to eval to false,
  * but float*_is_unordered() is still called. */
-FOP_COND_S(f,   (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0))
-FOP_COND_S(un,  float32_is_unordered(0, FST1, FST0, &env->fp_status))
-FOP_COND_S(eq,  !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status))
-FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_le(FST0, FST1, &env->fp_status))
+FOP_COND_S(f,   (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0))
+FOP_COND_S(un,  float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status))
+FOP_COND_S(eq,  !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)  || float32_eq(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)  || float32_lt(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)  || float32_le(FST0, FST1, &env->fpu->fp_status))
 /* NOTE: the comma operator will make "cond" to eval to false,
  * but float*_is_unordered() is still called. */
-FOP_COND_S(sf,  (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0))
-FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status))
-FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND_S(lt,  !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND_S(le,  !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status))
-FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_le(FST0, FST1, &env->fp_status))
+FOP_COND_S(sf,  (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0))
+FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status))
+FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)  || float32_eq(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(lt,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)  || float32_lt(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(le,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)  || float32_le(FST0, FST1, &env->fpu->fp_status))
 
 #define FOP_COND_PS(op, condl, condh)          \
 void do_cmp_ps_ ## op (long cc)                \
@@ -1233,13 +1254,13 @@ void do_cmp_ps_ ## op (long cc)                \
     int ch = condh;                            \
     update_fcr31();                            \
     if (cl)                                    \
-        SET_FP_COND(cc, env);                  \
+        SET_FP_COND(cc, env->fpu);             \
     else                                       \
-        CLEAR_FP_COND(cc, env);                \
+        CLEAR_FP_COND(cc, env->fpu);           \
     if (ch)                                    \
-        SET_FP_COND(cc + 1, env);              \
+        SET_FP_COND(cc + 1, env->fpu);         \
     else                                       \
-        CLEAR_FP_COND(cc + 1, env);            \
+        CLEAR_FP_COND(cc + 1, env->fpu);       \
 }                                              \
 void do_cmpabs_ps_ ## op (long cc)             \
 {                                              \
@@ -1252,48 +1273,48 @@ void do_cmpabs_ps_ ## op (long cc)             \
     ch = condh;                                \
     update_fcr31();                            \
     if (cl)                                    \
-        SET_FP_COND(cc, env);                  \
+        SET_FP_COND(cc, env->fpu);             \
     else                                       \
-        CLEAR_FP_COND(cc, env);                \
+        CLEAR_FP_COND(cc, env->fpu);           \
     if (ch)                                    \
-        SET_FP_COND(cc + 1, env);              \
+        SET_FP_COND(cc + 1, env->fpu);         \
     else                                       \
-        CLEAR_FP_COND(cc + 1, env);            \
+        CLEAR_FP_COND(cc + 1, env->fpu);       \
 }
 
 /* NOTE: the comma operator will make "cond" to eval to false,
  * but float*_is_unordered() is still called. */
-FOP_COND_PS(f,   (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0),
-                 (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0))
-FOP_COND_PS(un,  float32_is_unordered(0, FST1, FST0, &env->fp_status),
-                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status))
-FOP_COND_PS(eq,  !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_eq(FST0, FST1, &env->fp_status),
-                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_eq(FST0, FST1, &env->fp_status),
-                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_lt(FST0, FST1, &env->fp_status),
-                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_lt(FST0, FST1, &env->fp_status),
-                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_le(FST0, FST1, &env->fp_status),
-                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_le(FST0, FST1, &env->fp_status),
-                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_le(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(f,   (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0),
+                 (float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status), 0))
+FOP_COND_PS(un,  float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status),
+                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status))
+FOP_COND_PS(eq,  !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_eq(FST0, FST1, &env->fpu->fp_status),
+                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_eq(FST0, FST1, &env->fpu->fp_status),
+                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_lt(FST0, FST1, &env->fpu->fp_status),
+                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_lt(FST0, FST1, &env->fpu->fp_status),
+                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_le(FST0, FST1, &env->fpu->fp_status),
+                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_le(FST0, FST1, &env->fpu->fp_status),
+                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
 /* NOTE: the comma operator will make "cond" to eval to false,
  * but float*_is_unordered() is still called. */
-FOP_COND_PS(sf,  (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0),
-                 (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0))
-FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status),
-                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status))
-FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_eq(FST0, FST1, &env->fp_status),
-                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_eq(FST0, FST1, &env->fp_status),
-                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(lt,  !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_lt(FST0, FST1, &env->fp_status),
-                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_lt(FST0, FST1, &env->fp_status),
-                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(le,  !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_le(FST0, FST1, &env->fp_status),
-                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_le(FST0, FST1, &env->fp_status),
-                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_le(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(sf,  (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0),
+                 (float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status), 0))
+FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status),
+                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status))
+FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_eq(FST0, FST1, &env->fpu->fp_status),
+                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_eq(FST0, FST1, &env->fpu->fp_status),
+                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(lt,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_lt(FST0, FST1, &env->fpu->fp_status),
+                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_lt(FST0, FST1, &env->fpu->fp_status),
+                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(le,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_le(FST0, FST1, &env->fpu->fp_status),
+                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_le(FST0, FST1, &env->fpu->fp_status),
+                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
index 8236acc18e0a0d2f2114d412d865e576b3b4d12f..41d954c1db4a0084931e8176a6ed29626b7504c3 100644 (file)
 #if defined(REG)
 void glue(op_load_gpr_T0_gpr, REG) (void)
 {
-    T0 = env->gpr[REG];
+    T0 = env->gpr[REG][env->current_tc];
     RETURN();
 }
 
 void glue(op_store_T0_gpr_gpr, REG) (void)
 {
-    env->gpr[REG] = T0;
+    env->gpr[REG][env->current_tc] = T0;
     RETURN();
 }
 
 void glue(op_load_gpr_T1_gpr, REG) (void)
 {
-    T1 = env->gpr[REG];
+    T1 = env->gpr[REG][env->current_tc];
     RETURN();
 }
 
 void glue(op_store_T1_gpr_gpr, REG) (void)
 {
-    env->gpr[REG] = T1;
+    env->gpr[REG][env->current_tc] = T1;
     RETURN();
 }
 
 void glue(op_load_gpr_T2_gpr, REG) (void)
 {
-    T2 = env->gpr[REG];
+    T2 = env->gpr[REG][env->current_tc];
+    RETURN();
+}
+
+
+void glue(op_load_srsgpr_T0_gpr, REG) (void)
+{
+    T0 = env->gpr[REG][(env->CP0_SRSCtl >> CP0SRSCtl_PSS) & 0xf];
+    RETURN();
+}
+
+void glue(op_store_T0_srsgpr_gpr, REG) (void)
+{
+    env->gpr[REG][(env->CP0_SRSCtl >> CP0SRSCtl_PSS) & 0xf] = T0;
     RETURN();
 }
 #endif
index 07dca145954e47f01a9f08b468cd2165d7f97099..c87f2c9874d45768bd6de6d4140984bffdfbbba1 100644 (file)
@@ -266,6 +266,8 @@ enum {
     OPC_DINSM    = 0x05 | OPC_SPECIAL3,
     OPC_DINSU    = 0x06 | OPC_SPECIAL3,
     OPC_DINS     = 0x07 | OPC_SPECIAL3,
+    OPC_FORK     = 0x08 | OPC_SPECIAL3,
+    OPC_YIELD    = 0x09 | OPC_SPECIAL3,
     OPC_BSHFL    = 0x20 | OPC_SPECIAL3,
     OPC_DBSHFL   = 0x24 | OPC_SPECIAL3,
     OPC_RDHWR    = 0x3B | OPC_SPECIAL3,
@@ -296,8 +298,10 @@ enum {
     OPC_DMFC0    = (0x01 << 21) | OPC_CP0,
     OPC_MTC0     = (0x04 << 21) | OPC_CP0,
     OPC_DMTC0    = (0x05 << 21) | OPC_CP0,
+    OPC_MFTR     = (0x08 << 21) | OPC_CP0,
     OPC_RDPGPR   = (0x0A << 21) | OPC_CP0,
     OPC_MFMC0    = (0x0B << 21) | OPC_CP0,
+    OPC_MTTR     = (0x0C << 21) | OPC_CP0,
     OPC_WRPGPR   = (0x0E << 21) | OPC_CP0,
     OPC_C0       = (0x10 << 21) | OPC_CP0,
     OPC_C0_FIRST = (0x10 << 21) | OPC_CP0,
@@ -308,6 +312,10 @@ enum {
 #define MASK_MFMC0(op)     MASK_CP0(op) | (op & 0xFFFF)
 
 enum {
+    OPC_DMT      = 0x01 | (0 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0,
+    OPC_EMT      = 0x01 | (1 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0,
+    OPC_DVPE     = 0x01 | (0 << 5) | OPC_MFMC0,
+    OPC_EVPE     = 0x01 | (1 << 5) | OPC_MFMC0,
     OPC_DI       = (0 << 5) | (0x0C << 11) | OPC_MFMC0,
     OPC_EI       = (1 << 5) | (0x0C << 11) | OPC_MFMC0,
 };
@@ -441,6 +449,10 @@ GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
 GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
 GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
 
+/* Moves to/from shadow registers */
+GEN32(gen_op_load_srsgpr_T0, gen_op_load_srsgpr_T0_gpr);
+GEN32(gen_op_store_T0_srsgpr, gen_op_store_T0_srsgpr_gpr);
+
 static const char *fregnames[] =
     { "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
       "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
@@ -569,6 +581,15 @@ do {                                                                          \
     }                                                                         \
 } while (0)
 
+#define GEN_LOAD_SRSREG_TN(Tn, Rn)                                            \
+do {                                                                          \
+    if (Rn == 0) {                                                            \
+        glue(gen_op_reset_, Tn)();                                            \
+    } else {                                                                  \
+        glue(gen_op_load_srsgpr_, Tn)(Rn);                                    \
+    }                                                                         \
+} while (0)
+
 #ifdef TARGET_MIPS64
 #define GEN_LOAD_IMM_TN(Tn, Imm)                                              \
 do {                                                                          \
@@ -598,6 +619,13 @@ do {                                                                          \
     }                                                                         \
 } while (0)
 
+#define GEN_STORE_TN_SRSREG(Rn, Tn)                                           \
+do {                                                                          \
+    if (Rn != 0) {                                                            \
+        glue(glue(gen_op_store_, Tn),_srsgpr)(Rn);                            \
+    }                                                                         \
+} while (0)
+
 #define GEN_LOAD_FREG_FTN(FTn, Fn)                                            \
 do {                                                                          \
     glue(gen_op_load_fpr_, FTn)(Fn);                                          \
@@ -740,6 +768,14 @@ static inline void check_mips_r2(CPUState *env, DisasContext *ctx)
         generate_exception(ctx, EXCP_RI);
 }
 
+/* This code generates a "reserved instruction" exception if the
+   CPU is not MIPS MT capable. */
+static inline void check_mips_mt(CPUState *env, DisasContext *ctx)
+{
+    if (!(env->CP0_Config3 & (1 << CP0C3_MT)))
+        generate_exception(ctx, EXCP_RI);
+}
+
 #if defined(CONFIG_USER_ONLY)
 #define op_ldst(name)        gen_op_##name##_raw()
 #define OP_LD_TABLE(width)
@@ -806,8 +842,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
         gen_op_addr_add();
     }
     /* Don't do NOP if destination is zero: we must perform the actual
-     * memory access
-     */
+       memory access. */
     switch (opc) {
 #ifdef TARGET_MIPS64
     case OPC_LWU:
@@ -958,8 +993,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
         gen_op_addr_add();
     }
     /* Don't do NOP if destination is zero: we must perform the actual
-     * memory access
-     */
+       memory access. */
     switch (opc) {
     case OPC_LWC1:
         op_ldst(lwc1);
@@ -997,9 +1031,8 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
     const char *opn = "imm arith";
 
     if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) {
-        /* if no destination, treat it as a NOP 
-         * For addi, we must generate the overflow exception when needed.
-         */
+        /* If no destination, treat it as a NOP.
+           For addi, we must generate the overflow exception when needed. */
         MIPS_DEBUG("NOP");
         return;
     }
@@ -1175,9 +1208,8 @@ static void gen_arith (DisasContext *ctx, uint32_t opc,
 
     if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
        && opc != OPC_DADD && opc != OPC_DSUB) {
-        /* if no destination, treat it as a NOP 
-         * For add & sub, we must generate the overflow exception when needed.
-         */
+        /* If no destination, treat it as a NOP.
+           For add & sub, we must generate the overflow exception when needed. */
         MIPS_DEBUG("NOP");
         return;
     }
@@ -1324,29 +1356,29 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
     const char *opn = "hilo";
 
     if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
-        /* Treat as a NOP */
+        /* Treat as NOP. */
         MIPS_DEBUG("NOP");
         return;
     }
     switch (opc) {
     case OPC_MFHI:
-        gen_op_load_HI();
+        gen_op_load_HI(0);
         GEN_STORE_TN_REG(reg, T0);
         opn = "mfhi";
         break;
     case OPC_MFLO:
-        gen_op_load_LO();
+        gen_op_load_LO(0);
         GEN_STORE_TN_REG(reg, T0);
         opn = "mflo";
         break;
     case OPC_MTHI:
         GEN_LOAD_REG_TN(T0, reg);
-        gen_op_store_HI();
+        gen_op_store_HI(0);
         opn = "mthi";
         break;
     case OPC_MTLO:
         GEN_LOAD_REG_TN(T0, reg);
-        gen_op_store_LO();
+        gen_op_store_LO(0);
         opn = "mtlo";
         break;
     default:
@@ -1428,7 +1460,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc,
 {
     const char *opn = "CLx";
     if (rd == 0) {
-        /* Treat as a NOP */
+        /* Treat as NOP. */
         MIPS_DEBUG("NOP");
         return;
     }
@@ -1514,7 +1546,7 @@ static void gen_trap (DisasContext *ctx, uint32_t opc,
         case OPC_TLTIU: /* r0 < 0  unsigned  */
         case OPC_TNE:   /* rs != rs          */
         case OPC_TNEI:  /* r0 != 0           */
-            /* Never trap: treat as NOP */
+            /* Never trap: treat as NOP. */
             return;
         default:
             MIPS_INVAL("trap");
@@ -1674,7 +1706,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
         case OPC_BNE:     /* rx != rx        */
         case OPC_BGTZ:    /* 0 > 0           */
         case OPC_BLTZ:    /* 0 < 0           */
-            /* Treated as NOP */
+            /* Treat as NOP. */
             MIPS_DEBUG("bnever (NOP)");
             return;
         case OPC_BLTZAL:  /* 0 < 0           */
@@ -1886,17 +1918,20 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "Index";
             break;
         case 1:
-//            gen_op_mfc0_mvpcontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_mvpcontrol();
             rn = "MVPControl";
-//            break;
+            break;
         case 2:
-//            gen_op_mfc0_mvpconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_mvpconf0();
             rn = "MVPConf0";
-//            break;
+            break;
         case 3:
-//            gen_op_mfc0_mvpconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_mvpconf1();
             rn = "MVPConf1";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -1908,33 +1943,40 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "Random";
             break;
         case 1:
-//            gen_op_mfc0_vpecontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpecontrol();
             rn = "VPEControl";
-//            break;
+            break;
         case 2:
-//            gen_op_mfc0_vpeconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeconf0();
             rn = "VPEConf0";
-//            break;
+            break;
         case 3:
-//            gen_op_mfc0_vpeconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeconf1();
             rn = "VPEConf1";
-//            break;
+            break;
         case 4:
-//            gen_op_mfc0_YQMask(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_yqmask();
             rn = "YQMask";
-//            break;
+            break;
         case 5:
-//            gen_op_mfc0_vpeschedule(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeschedule();
             rn = "VPESchedule";
-//            break;
+            break;
         case 6:
-//            gen_op_mfc0_vpeschefback(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeschefback();
             rn = "VPEScheFBack";
-//            break;
+            break;
         case 7:
-//            gen_op_mfc0_vpeopt(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeopt();
             rn = "VPEOpt";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -1946,33 +1988,40 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "EntryLo0";
             break;
         case 1:
-//            gen_op_mfc0_tcstatus(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcstatus();
             rn = "TCStatus";
-//            break;
+            break;
         case 2:
-//            gen_op_mfc0_tcbind(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcbind();
             rn = "TCBind";
-//            break;
+            break;
         case 3:
-//            gen_op_mfc0_tcrestart(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcrestart();
             rn = "TCRestart";
-//            break;
+            break;
         case 4:
-//            gen_op_mfc0_tchalt(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tchalt();
             rn = "TCHalt";
-//            break;
+            break;
         case 5:
-//            gen_op_mfc0_tccontext(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tccontext();
             rn = "TCContext";
-//            break;
+            break;
         case 6:
-//            gen_op_mfc0_tcschedule(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcschedule();
             rn = "TCSchedule";
-//            break;
+            break;
         case 7:
-//            gen_op_mfc0_tcschefback(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcschefback();
             rn = "TCScheFBack";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -2023,25 +2072,25 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "Wired";
             break;
         case 1:
-//            gen_op_mfc0_srsconf0(); /* shadow registers */
+            gen_op_mfc0_srsconf0();
             rn = "SRSConf0";
-//            break;
+            break;
         case 2:
-//            gen_op_mfc0_srsconf1(); /* shadow registers */
+            gen_op_mfc0_srsconf1();
             rn = "SRSConf1";
-//            break;
+            break;
         case 3:
-//            gen_op_mfc0_srsconf2(); /* shadow registers */
+            gen_op_mfc0_srsconf2();
             rn = "SRSConf2";
-//            break;
+            break;
         case 4:
-//            gen_op_mfc0_srsconf3(); /* shadow registers */
+            gen_op_mfc0_srsconf3();
             rn = "SRSConf3";
-//            break;
+            break;
         case 5:
-//            gen_op_mfc0_srsconf4(); /* shadow registers */
+            gen_op_mfc0_srsconf4();
             rn = "SRSConf4";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -2430,17 +2479,20 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "Index";
             break;
         case 1:
-//            gen_op_mtc0_mvpcontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_mvpcontrol();
             rn = "MVPControl";
-//            break;
+            break;
         case 2:
-//            gen_op_mtc0_mvpconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            /* ignored */
             rn = "MVPConf0";
-//            break;
+            break;
         case 3:
-//            gen_op_mtc0_mvpconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            /* ignored */
             rn = "MVPConf1";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -2452,33 +2504,40 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "Random";
             break;
         case 1:
-//            gen_op_mtc0_vpecontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpecontrol();
             rn = "VPEControl";
-//            break;
+            break;
         case 2:
-//            gen_op_mtc0_vpeconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeconf0();
             rn = "VPEConf0";
-//            break;
+            break;
         case 3:
-//            gen_op_mtc0_vpeconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeconf1();
             rn = "VPEConf1";
-//            break;
+            break;
         case 4:
-//            gen_op_mtc0_YQMask(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_yqmask();
             rn = "YQMask";
-//            break;
+            break;
         case 5:
-//            gen_op_mtc0_vpeschedule(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeschedule();
             rn = "VPESchedule";
-//            break;
+            break;
         case 6:
-//            gen_op_mtc0_vpeschefback(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeschefback();
             rn = "VPEScheFBack";
-//            break;
+            break;
         case 7:
-//            gen_op_mtc0_vpeopt(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeopt();
             rn = "VPEOpt";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -2490,33 +2549,40 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "EntryLo0";
             break;
         case 1:
-//            gen_op_mtc0_tcstatus(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcstatus();
             rn = "TCStatus";
-//            break;
+            break;
         case 2:
-//            gen_op_mtc0_tcbind(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcbind();
             rn = "TCBind";
-//            break;
+            break;
         case 3:
-//            gen_op_mtc0_tcrestart(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcrestart();
             rn = "TCRestart";
-//            break;
+            break;
         case 4:
-//            gen_op_mtc0_tchalt(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tchalt();
             rn = "TCHalt";
-//            break;
+            break;
         case 5:
-//            gen_op_mtc0_tccontext(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tccontext();
             rn = "TCContext";
-//            break;
+            break;
         case 6:
-//            gen_op_mtc0_tcschedule(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcschedule();
             rn = "TCSchedule";
-//            break;
+            break;
         case 7:
-//            gen_op_mtc0_tcschefback(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcschefback();
             rn = "TCScheFBack";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -2567,25 +2633,25 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "Wired";
             break;
         case 1:
-//            gen_op_mtc0_srsconf0(); /* shadow registers */
+            gen_op_mtc0_srsconf0();
             rn = "SRSConf0";
-//            break;
+            break;
         case 2:
-//            gen_op_mtc0_srsconf1(); /* shadow registers */
+            gen_op_mtc0_srsconf1();
             rn = "SRSConf1";
-//            break;
+            break;
         case 3:
-//            gen_op_mtc0_srsconf2(); /* shadow registers */
+            gen_op_mtc0_srsconf2();
             rn = "SRSConf2";
-//            break;
+            break;
         case 4:
-//            gen_op_mtc0_srsconf3(); /* shadow registers */
+            gen_op_mtc0_srsconf3();
             rn = "SRSConf3";
-//            break;
+            break;
         case 5:
-//            gen_op_mtc0_srsconf4(); /* shadow registers */
+            gen_op_mtc0_srsconf4();
             rn = "SRSConf4";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -3006,17 +3072,20 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "Index";
             break;
         case 1:
-//            gen_op_dmfc0_mvpcontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_mvpcontrol();
             rn = "MVPControl";
-//            break;
+            break;
         case 2:
-//            gen_op_dmfc0_mvpconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_mvpconf0();
             rn = "MVPConf0";
-//            break;
+            break;
         case 3:
-//            gen_op_dmfc0_mvpconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_mvpconf1();
             rn = "MVPConf1";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -3028,33 +3097,40 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "Random";
             break;
         case 1:
-//            gen_op_dmfc0_vpecontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpecontrol();
             rn = "VPEControl";
-//            break;
+            break;
         case 2:
-//            gen_op_dmfc0_vpeconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeconf0();
             rn = "VPEConf0";
-//            break;
+            break;
         case 3:
-//            gen_op_dmfc0_vpeconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeconf1();
             rn = "VPEConf1";
-//            break;
+            break;
         case 4:
-//            gen_op_dmfc0_YQMask(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_yqmask();
             rn = "YQMask";
-//            break;
+            break;
         case 5:
-//            gen_op_dmfc0_vpeschedule(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_vpeschedule();
             rn = "VPESchedule";
-//            break;
+            break;
         case 6:
-//            gen_op_dmfc0_vpeschefback(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_vpeschefback();
             rn = "VPEScheFBack";
-//            break;
+            break;
         case 7:
-//            gen_op_dmfc0_vpeopt(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeopt();
             rn = "VPEOpt";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -3066,33 +3142,40 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "EntryLo0";
             break;
         case 1:
-//            gen_op_dmfc0_tcstatus(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcstatus();
             rn = "TCStatus";
-//            break;
+            break;
         case 2:
-//            gen_op_dmfc0_tcbind(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcbind();
             rn = "TCBind";
-//            break;
+            break;
         case 3:
-//            gen_op_dmfc0_tcrestart(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_tcrestart();
             rn = "TCRestart";
-//            break;
+            break;
         case 4:
-//            gen_op_dmfc0_tchalt(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_tchalt();
             rn = "TCHalt";
-//            break;
+            break;
         case 5:
-//            gen_op_dmfc0_tccontext(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_tccontext();
             rn = "TCContext";
-//            break;
+            break;
         case 6:
-//            gen_op_dmfc0_tcschedule(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_tcschedule();
             rn = "TCSchedule";
-//            break;
+            break;
         case 7:
-//            gen_op_dmfc0_tcschefback(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_tcschefback();
             rn = "TCScheFBack";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -3143,25 +3226,25 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "Wired";
             break;
         case 1:
-//            gen_op_dmfc0_srsconf0(); /* shadow registers */
+            gen_op_mfc0_srsconf0();
             rn = "SRSConf0";
-//            break;
+            break;
         case 2:
-//            gen_op_dmfc0_srsconf1(); /* shadow registers */
+            gen_op_mfc0_srsconf1();
             rn = "SRSConf1";
-//            break;
+            break;
         case 3:
-//            gen_op_dmfc0_srsconf2(); /* shadow registers */
+            gen_op_mfc0_srsconf2();
             rn = "SRSConf2";
-//            break;
+            break;
         case 4:
-//            gen_op_dmfc0_srsconf3(); /* shadow registers */
+            gen_op_mfc0_srsconf3();
             rn = "SRSConf3";
-//            break;
+            break;
         case 5:
-//            gen_op_dmfc0_srsconf4(); /* shadow registers */
+            gen_op_mfc0_srsconf4();
             rn = "SRSConf4";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -3237,7 +3320,7 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             break;
         case 3:
             check_mips_r2(env, ctx);
-            gen_op_mfc0_srsmap(); /* shadow registers */
+            gen_op_mfc0_srsmap();
             rn = "SRSMap";
             break;
         default:
@@ -3537,17 +3620,20 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "Index";
             break;
         case 1:
-//            gen_op_mtc0_mvpcontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_mvpcontrol();
             rn = "MVPControl";
-//            break;
+            break;
         case 2:
-//            gen_op_mtc0_mvpconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            /* ignored */
             rn = "MVPConf0";
-//            break;
+            break;
         case 3:
-//            gen_op_mtc0_mvpconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            /* ignored */
             rn = "MVPConf1";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -3559,33 +3645,40 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "Random";
             break;
         case 1:
-//            gen_op_mtc0_vpecontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpecontrol();
             rn = "VPEControl";
-//            break;
+            break;
         case 2:
-//            gen_op_mtc0_vpeconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeconf0();
             rn = "VPEConf0";
-//            break;
+            break;
         case 3:
-//            gen_op_mtc0_vpeconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeconf1();
             rn = "VPEConf1";
-//            break;
+            break;
         case 4:
-//            gen_op_mtc0_YQMask(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_yqmask();
             rn = "YQMask";
-//            break;
+            break;
         case 5:
-//            gen_op_mtc0_vpeschedule(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeschedule();
             rn = "VPESchedule";
-//            break;
+            break;
         case 6:
-//            gen_op_mtc0_vpeschefback(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeschefback();
             rn = "VPEScheFBack";
-//            break;
+            break;
         case 7:
-//            gen_op_mtc0_vpeopt(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeopt();
             rn = "VPEOpt";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -3597,33 +3690,40 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "EntryLo0";
             break;
         case 1:
-//            gen_op_mtc0_tcstatus(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcstatus();
             rn = "TCStatus";
-//            break;
+            break;
         case 2:
-//            gen_op_mtc0_tcbind(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcbind();
             rn = "TCBind";
-//            break;
+            break;
         case 3:
-//            gen_op_mtc0_tcrestart(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcrestart();
             rn = "TCRestart";
-//            break;
+            break;
         case 4:
-//            gen_op_mtc0_tchalt(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tchalt();
             rn = "TCHalt";
-//            break;
+            break;
         case 5:
-//            gen_op_mtc0_tccontext(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tccontext();
             rn = "TCContext";
-//            break;
+            break;
         case 6:
-//            gen_op_mtc0_tcschedule(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcschedule();
             rn = "TCSchedule";
-//            break;
+            break;
         case 7:
-//            gen_op_mtc0_tcschefback(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcschefback();
             rn = "TCScheFBack";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -3674,25 +3774,25 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
             rn = "Wired";
             break;
         case 1:
-//            gen_op_mtc0_srsconf0(); /* shadow registers */
+            gen_op_mtc0_srsconf0();
             rn = "SRSConf0";
-//            break;
+            break;
         case 2:
-//            gen_op_mtc0_srsconf1(); /* shadow registers */
+            gen_op_mtc0_srsconf1();
             rn = "SRSConf1";
-//            break;
+            break;
         case 3:
-//            gen_op_mtc0_srsconf2(); /* shadow registers */
+            gen_op_mtc0_srsconf2();
             rn = "SRSConf2";
-//            break;
+            break;
         case 4:
-//            gen_op_mtc0_srsconf3(); /* shadow registers */
+            gen_op_mtc0_srsconf3();
             rn = "SRSConf3";
-//            break;
+            break;
         case 5:
-//            gen_op_mtc0_srsconf4(); /* shadow registers */
+            gen_op_mtc0_srsconf4();
             rn = "SRSConf4";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -4086,6 +4186,334 @@ die:
 }
 #endif /* TARGET_MIPS64 */
 
+static void gen_mftr(CPUState *env, DisasContext *ctx, int rt,
+                     int u, int sel, int h)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    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))))
+        gen_op_set_T0(-1);
+    else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
+             (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC)))
+        gen_op_set_T0(-1);
+    else if (u == 0) {
+        switch (rt) {
+        case 2:
+            switch (sel) {
+            case 1:
+                gen_op_mftc0_tcstatus();
+                break;
+            case 2:
+                gen_op_mftc0_tcbind();
+                break;
+            case 3:
+                gen_op_mftc0_tcrestart();
+                break;
+            case 4:
+                gen_op_mftc0_tchalt();
+                break;
+            case 5:
+                gen_op_mftc0_tccontext();
+                break;
+            case 6:
+                gen_op_mftc0_tcschedule();
+                break;
+            case 7:
+                gen_op_mftc0_tcschefback();
+                break;
+            default:
+                gen_mfc0(env, ctx, rt, sel);
+                break;
+            }
+            break;
+        case 10:
+            switch (sel) {
+            case 0:
+                gen_op_mftc0_entryhi();
+                break;
+            default:
+                gen_mfc0(env, ctx, rt, sel);
+                break;
+            }
+        case 12:
+            switch (sel) {
+            case 0:
+                gen_op_mftc0_status();
+                break;
+            default:
+                gen_mfc0(env, ctx, rt, sel);
+                break;
+            }
+        case 23:
+            switch (sel) {
+            case 0:
+                gen_op_mftc0_debug();
+                break;
+            default:
+                gen_mfc0(env, ctx, rt, sel);
+                break;
+            }
+            break;
+        default:
+            gen_mfc0(env, ctx, rt, sel);
+        }
+    } else switch (sel) {
+    /* GPR registers. */
+    case 0:
+        gen_op_mftgpr(rt);
+        break;
+    /* Auxiliary CPU registers */
+    case 1:
+        switch (rt) {
+        case 0:
+            gen_op_mftlo(0);
+            break;
+        case 1:
+            gen_op_mfthi(0);
+            break;
+        case 2:
+            gen_op_mftacx(0);
+            break;
+        case 4:
+            gen_op_mftlo(1);
+            break;
+        case 5:
+            gen_op_mfthi(1);
+            break;
+        case 6:
+            gen_op_mftacx(1);
+            break;
+        case 8:
+            gen_op_mftlo(2);
+            break;
+        case 9:
+            gen_op_mfthi(2);
+            break;
+        case 10:
+            gen_op_mftacx(2);
+            break;
+        case 12:
+            gen_op_mftlo(3);
+            break;
+        case 13:
+            gen_op_mfthi(3);
+            break;
+        case 14:
+            gen_op_mftacx(3);
+            break;
+        case 16:
+            gen_op_mftdsp();
+            break;
+        default:
+            goto die;
+        }
+        break;
+    /* Floating point (COP1). */
+    case 2:
+        /* XXX: For now we support only a single FPU context. */
+        if (h == 0) {
+            GEN_LOAD_FREG_FTN(WT0, rt);
+            gen_op_mfc1();
+        } else {
+            GEN_LOAD_FREG_FTN(WTH0, rt);
+            gen_op_mfhc1();
+        }
+        break;
+    case 3:
+        /* XXX: For now we support only a single FPU context. */
+        gen_op_cfc1(rt);
+        break;
+    /* COP2: Not implemented. */
+    case 4:
+    case 5:
+        /* fall through */
+    default:
+        goto die;
+    }
+#if defined MIPS_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n",
+                rt, u, sel, h);
+    }
+#endif
+    return;
+
+die:
+#if defined MIPS_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n",
+                rt, u, sel, h);
+    }
+#endif
+    generate_exception(ctx, EXCP_RI);
+}
+
+static void gen_mttr(CPUState *env, DisasContext *ctx, int rd,
+                     int u, int sel, int h)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    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))))
+        /* NOP */ ;
+    else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
+             (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC)))
+        /* NOP */ ;
+    else if (u == 0) {
+        switch (rd) {
+        case 2:
+            switch (sel) {
+            case 1:
+                gen_op_mttc0_tcstatus();
+                break;
+            case 2:
+                gen_op_mttc0_tcbind();
+                break;
+            case 3:
+                gen_op_mttc0_tcrestart();
+                break;
+            case 4:
+                gen_op_mttc0_tchalt();
+                break;
+            case 5:
+                gen_op_mttc0_tccontext();
+                break;
+            case 6:
+                gen_op_mttc0_tcschedule();
+                break;
+            case 7:
+                gen_op_mttc0_tcschefback();
+                break;
+            default:
+                gen_mtc0(env, ctx, rd, sel);
+                break;
+            }
+            break;
+        case 10:
+            switch (sel) {
+            case 0:
+                gen_op_mttc0_entryhi();
+                break;
+            default:
+                gen_mtc0(env, ctx, rd, sel);
+                break;
+            }
+        case 12:
+            switch (sel) {
+            case 0:
+                gen_op_mttc0_status();
+                break;
+            default:
+                gen_mtc0(env, ctx, rd, sel);
+                break;
+            }
+        case 23:
+            switch (sel) {
+            case 0:
+                gen_op_mttc0_debug();
+                break;
+            default:
+                gen_mtc0(env, ctx, rd, sel);
+                break;
+            }
+            break;
+        default:
+            gen_mtc0(env, ctx, rd, sel);
+        }
+    } else switch (sel) {
+    /* GPR registers. */
+    case 0:
+        gen_op_mttgpr(rd);
+        break;
+    /* Auxiliary CPU registers */
+    case 1:
+        switch (rd) {
+        case 0:
+            gen_op_mttlo(0);
+            break;
+        case 1:
+            gen_op_mtthi(0);
+            break;
+        case 2:
+            gen_op_mttacx(0);
+            break;
+        case 4:
+            gen_op_mttlo(1);
+            break;
+        case 5:
+            gen_op_mtthi(1);
+            break;
+        case 6:
+            gen_op_mttacx(1);
+            break;
+        case 8:
+            gen_op_mttlo(2);
+            break;
+        case 9:
+            gen_op_mtthi(2);
+            break;
+        case 10:
+            gen_op_mttacx(2);
+            break;
+        case 12:
+            gen_op_mttlo(3);
+            break;
+        case 13:
+            gen_op_mtthi(3);
+            break;
+        case 14:
+            gen_op_mttacx(3);
+            break;
+        case 16:
+            gen_op_mttdsp();
+            break;
+        default:
+            goto die;
+        }
+        break;
+    /* Floating point (COP1). */
+    case 2:
+        /* XXX: For now we support only a single FPU context. */
+        if (h == 0) {
+            gen_op_mtc1();
+            GEN_STORE_FTN_FREG(rd, WT0);
+        } else {
+            gen_op_mthc1();
+            GEN_STORE_FTN_FREG(rd, WTH0);
+        }
+        break;
+    case 3:
+        /* XXX: For now we support only a single FPU context. */
+        gen_op_ctc1(rd);
+        break;
+    /* COP2: Not implemented. */
+    case 4:
+    case 5:
+        /* fall through */
+    default:
+        goto die;
+    }
+#if defined MIPS_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n",
+                rd, u, sel, h);
+    }
+#endif
+    return;
+
+die:
+#if defined MIPS_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n",
+                rd, u, sel, h);
+    }
+#endif
+    generate_exception(ctx, EXCP_RI);
+}
+
 static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int rd)
 {
     const char *opn = "ldst";
@@ -4093,7 +4521,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
     switch (opc) {
     case OPC_MFC0:
         if (rt == 0) {
-            /* Treat as NOP */
+            /* Treat as NOP. */
             return;
         }
         gen_mfc0(env, ctx, rd, ctx->opcode & 0x7);
@@ -4110,7 +4538,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
         if (!(ctx->hflags & MIPS_HFLAG_64))
             generate_exception(ctx, EXCP_RI);
         if (rt == 0) {
-            /* Treat as NOP */
+            /* Treat as NOP. */
             return;
         }
         gen_dmfc0(env, ctx, rd, ctx->opcode & 0x7);
@@ -4121,31 +4549,49 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
         if (!(ctx->hflags & MIPS_HFLAG_64))
             generate_exception(ctx, EXCP_RI);
         GEN_LOAD_REG_TN(T0, rt);
-        gen_dmtc0(env,ctx, rd, ctx->opcode & 0x7);
+        gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7);
         opn = "dmtc0";
         break;
 #endif
+    case OPC_MFTR:
+        check_mips_mt(env, ctx);
+        if (rd == 0) {
+            /* Treat as NOP. */
+            return;
+        }
+        gen_mftr(env, ctx, rt, (ctx->opcode >> 5) & 1,
+                 ctx->opcode & 0x7, (ctx->opcode >> 4) & 1);
+        gen_op_store_T0_gpr(rd);
+        opn = "mftr";
+        break;
+    case OPC_MTTR:
+        check_mips_mt(env, ctx);
+        GEN_LOAD_REG_TN(T0, rt);
+        gen_mttr(env, ctx, rd, (ctx->opcode >> 5) & 1,
+                 ctx->opcode & 0x7, (ctx->opcode >> 4) & 1);
+        opn = "mttr";
+        break;
     case OPC_TLBWI:
         opn = "tlbwi";
-        if (!env->do_tlbwi)
+        if (!env->tlb->do_tlbwi)
             goto die;
         gen_op_tlbwi();
         break;
     case OPC_TLBWR:
         opn = "tlbwr";
-        if (!env->do_tlbwr)
+        if (!env->tlb->do_tlbwr)
             goto die;
         gen_op_tlbwr();
         break;
     case OPC_TLBP:
         opn = "tlbp";
-        if (!env->do_tlbp)
+        if (!env->tlb->do_tlbp)
             goto die;
         gen_op_tlbp();
         break;
     case OPC_TLBR:
         opn = "tlbr";
-        if (!env->do_tlbr)
+        if (!env->tlb->do_tlbr)
             goto die;
         gen_op_tlbr();
         break;
@@ -4263,15 +4709,13 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
         opn = "mtc1";
         break;
     case OPC_CFC1:
-        GEN_LOAD_IMM_TN(T1, fs);
-        gen_op_cfc1();
+        gen_op_cfc1(fs);
         GEN_STORE_TN_REG(rt, T0);
         opn = "cfc1";
         break;
     case OPC_CTC1:
-        GEN_LOAD_IMM_TN(T1, fs);
         GEN_LOAD_REG_TN(T0, rt);
-        gen_op_ctc1();
+        gen_op_ctc1(fs);
         opn = "ctc1";
         break;
     case OPC_DMFC1:
@@ -5171,8 +5615,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
         gen_op_addr_add();
     }
     /* Don't do NOP if destination is zero: we must perform the actual
-     * memory access
-     */
+       memory access. */
     switch (opc) {
     case OPC_LWXC1:
         op_ldst(lwc1);
@@ -5456,7 +5899,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
 #endif
             break;
         case OPC_SYNC:
-            /* Treat as a noop. */
+            /* Treat as NOP. */
             break;
 
         case OPC_MOVCI:
@@ -5521,7 +5964,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
             } else {
                 generate_exception(ctx, EXCP_DBp);
             }
-            /* Treat as a noop */
+            /* Treat as NOP. */
             break;
 #ifdef TARGET_MIPS64
         case OPC_DCLZ ... OPC_DCLO:
@@ -5586,7 +6029,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
                 break;
             case 29:
 #if defined (CONFIG_USER_ONLY)
-                gen_op_tls_value ();
+                gen_op_tls_value();
                 break;
 #endif
             default:            /* Invalid */
@@ -5596,6 +6039,18 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
             }
             GEN_STORE_TN_REG(rt, T0);
             break;
+        case OPC_FORK:
+            check_mips_mt(env, ctx);
+            GEN_LOAD_REG_TN(T0, rt);
+            GEN_LOAD_REG_TN(T1, rs);
+            gen_op_fork();
+            break;
+        case OPC_YIELD:
+            check_mips_mt(env, ctx);
+            GEN_LOAD_REG_TN(T0, rs);
+            gen_op_yield();
+            GEN_STORE_TN_REG(rd, T0);
+            break;
 #ifdef TARGET_MIPS64
         case OPC_DEXTM ... OPC_DEXT:
         case OPC_DINSM ... OPC_DINS:
@@ -5642,7 +6097,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
             break;
         case OPC_SYNCI:
             check_mips_r2(env, ctx);
-            /* treat as noop */
+            /* Treat as NOP. */
             break;
         default:            /* Invalid */
             MIPS_INVAL("regimm");
@@ -5657,6 +6112,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
         switch (op1) {
         case OPC_MFC0:
         case OPC_MTC0:
+        case OPC_MFTR:
+        case OPC_MTTR:
 #ifdef TARGET_MIPS64
         case OPC_DMFC0:
         case OPC_DMTC0:
@@ -5670,6 +6127,22 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
             check_mips_r2(env, ctx);
             op2 = MASK_MFMC0(ctx->opcode);
             switch (op2) {
+            case OPC_DMT:
+                check_mips_mt(env, ctx);
+                gen_op_dmt();
+                break;
+            case OPC_EMT:
+                check_mips_mt(env, ctx);
+                gen_op_emt();
+                break;
+            case OPC_DVPE:
+                check_mips_mt(env, ctx);
+                gen_op_dvpe();
+                break;
+            case OPC_EVPE:
+                check_mips_mt(env, ctx);
+                gen_op_evpe();
+                break;
             case OPC_DI:
                 gen_op_di();
                 /* Stop translation as we may have switched the execution mode */
@@ -5688,11 +6161,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
             GEN_STORE_TN_REG(rt, T0);
             break;
         case OPC_RDPGPR:
+            check_mips_r2(env, ctx);
+            GEN_LOAD_SRSREG_TN(T0, rt);
+            GEN_STORE_TN_REG(rd, T0);
+            break;
         case OPC_WRPGPR:
             check_mips_r2(env, ctx);
-            /* Shadow registers not implemented. */
             GEN_LOAD_REG_TN(T0, rt);
-            GEN_STORE_TN_REG(rd, T0);
+            GEN_STORE_TN_SRSREG(rd, T0);
             break;
         default:
             MIPS_INVAL("cp0");
@@ -5719,10 +6195,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
          gen_ldst(ctx, op, rt, rs, imm);
          break;
     case OPC_CACHE:
-        /* Treat as a noop */
+        /* Treat as NOP. */
         break;
     case OPC_PREF:
-        /* Treat as a noop */
+        /* Treat as NOP. */
         break;
 
     /* Floating point (COP1). */
@@ -5807,7 +6283,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
                 gen_flt3_ldst(ctx, op1, sa, rd, rs, rt);
                 break;
             case OPC_PREFX:
-                /* treat as noop */
+                /* Treat as NOP. */
                 break;
             case OPC_ALNV_PS:
             case OPC_MADD_S:
@@ -6079,13 +6555,14 @@ void fpu_dump_state(CPUState *env, FILE *f,
 
 
     fpu_fprintf(f, "CP1 FCR0 0x%08x  FCR31 0x%08x  SR.FR %d  fp_status 0x%08x(0x%02x)\n",
-                env->fcr0, env->fcr31, is_fpu64, env->fp_status, get_float_exception_flags(&env->fp_status));
-    fpu_fprintf(f, "FT0: "); printfpr(&env->ft0);
-    fpu_fprintf(f, "FT1: "); printfpr(&env->ft1);
-    fpu_fprintf(f, "FT2: "); printfpr(&env->ft2);
+                env->fpu->fcr0, env->fpu->fcr31, is_fpu64, env->fpu->fp_status,
+                get_float_exception_flags(&env->fpu->fp_status));
+    fpu_fprintf(f, "FT0: "); printfpr(&env->fpu->ft0);
+    fpu_fprintf(f, "FT1: "); printfpr(&env->fpu->ft1);
+    fpu_fprintf(f, "FT2: "); printfpr(&env->fpu->ft2);
     for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
         fpu_fprintf(f, "%3s: ", fregnames[i]);
-        printfpr(&env->fpr[i]);
+        printfpr(&env->fpu->fpr[i]);
     }
 
 #undef printfpr
@@ -6095,7 +6572,7 @@ void dump_fpu (CPUState *env)
 {
     if (loglevel) { 
        fprintf(logfile, "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->HI, env->LO, env->hflags, env->btarget, env->bcond);
+               env->PC[env->current_tc], env->HI[0][env->current_tc], env->LO[0][env->current_tc], env->hflags, env->btarget, env->bcond);
        fpu_dump_state(env, logfile, fprintf, 0);
     }
 }
@@ -6112,18 +6589,18 @@ void cpu_mips_check_sign_extensions (CPUState *env, FILE *f,
 {
     int i;
 
-    if (!SIGN_EXT_P(env->PC))
-        cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC);
-    if (!SIGN_EXT_P(env->HI))
-        cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI);
-    if (!SIGN_EXT_P(env->LO))
-        cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO);
+    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]))
+        cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI[env->current_tc]);
+    if (!SIGN_EXT_P(env->LO[env->current_tc]))
+        cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO[env->current_tc]);
     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[i]))
-            cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i]);
+        if (!SIGN_EXT_P(env->gpr[i][env->current_tc]))
+            cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i][env->current_tc]);
     }
 
     if (!SIGN_EXT_P(env->CP0_EPC))
@@ -6140,11 +6617,11 @@ void cpu_dump_state (CPUState *env, FILE *f,
     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->HI, env->LO, env->hflags, env->btarget, env->bcond);
+                env->PC[env->current_tc], env->HI[env->current_tc], env->LO[env->current_tc], 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[i]);
+        cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[i][env->current_tc]);
         if ((i & 3) == 3)
             cpu_fprintf(f, "\n");
     }
@@ -6183,12 +6660,12 @@ void cpu_reset (CPUMIPSState *env)
     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 - 4;
+        env->CP0_ErrorEPC = env->PC[env->current_tc] - 4;
     } else {
-        env->CP0_ErrorEPC = env->PC;
+        env->CP0_ErrorEPC = env->PC[env->current_tc];
     }
     env->hflags = 0;
-    env->PC = (int32_t)0xBFC00000;
+    env->PC[env->current_tc] = (int32_t)0xBFC00000;
     env->CP0_Wired = 0;
     /* SMP not implemented */
     env->CP0_EBase = 0x80000000;
index d327312e556912d2bffd7e86fd7dccd11fcf50ad..a9e931264238726b0d393b39d0f495e1a6fc4787 100644 (file)
 
 /* No config4, no DSP ASE, no large physaddr,
    no external interrupt controller, no vectored interupts,
-   no 1kb pages, no MT ASE, no SmartMIPS ASE, no trace logic */
+   no 1kb pages, no SmartMIPS ASE, no trace logic */
 #define MIPS_CONFIG3                                              \
 ((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) |          \
  (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) |        \
- (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL))
+ (0 << CP0C3_SM) | (0 << CP0C3_TL))
 
 /* Define a implementation number of 1.
    Define a major version 1, minor version 0. */
@@ -65,9 +65,21 @@ struct mips_def_t {
     int32_t CP0_Config7;
     int32_t SYNCI_Step;
     int32_t CCRes;
-    int32_t Status_rw_bitmask;
+    int32_t CP0_Status_rw_bitmask;
+    int32_t CP0_TCStatus_rw_bitmask;
+    int32_t CP0_SRSCtl;
     int32_t CP1_fcr0;
     int32_t SEGBITS;
+    int32_t CP0_SRSConf0_rw_bitmask;
+    int32_t CP0_SRSConf0;
+    int32_t CP0_SRSConf1_rw_bitmask;
+    int32_t CP0_SRSConf1;
+    int32_t CP0_SRSConf2_rw_bitmask;
+    int32_t CP0_SRSConf2;
+    int32_t CP0_SRSConf3_rw_bitmask;
+    int32_t CP0_SRSConf3;
+    int32_t CP0_SRSConf4_rw_bitmask;
+    int32_t CP0_SRSConf4;
 };
 
 /*****************************************************************************/
@@ -85,7 +97,7 @@ static mips_def_t mips_defs[] =
         .CP0_Config3 = MIPS_CONFIG3,
         .SYNCI_Step = 32,
         .CCRes = 2,
-        .Status_rw_bitmask = 0x3278FF17,
+        .CP0_Status_rw_bitmask = 0x1278FF17,
     },
     {
         .name = "4KEcR1",
@@ -98,7 +110,7 @@ static mips_def_t mips_defs[] =
         .CP0_Config3 = MIPS_CONFIG3,
         .SYNCI_Step = 32,
         .CCRes = 2,
-        .Status_rw_bitmask = 0x3278FF17,
+        .CP0_Status_rw_bitmask = 0x1278FF17,
     },
     {
         .name = "4KEc",
@@ -108,10 +120,10 @@ static mips_def_t mips_defs[] =
                    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
                    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
         .CP0_Config2 = MIPS_CONFIG2,
-        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
         .SYNCI_Step = 32,
         .CCRes = 2,
-        .Status_rw_bitmask = 0x3278FF17,
+        .CP0_Status_rw_bitmask = 0x1278FF17,
     },
     {
         .name = "24Kc",
@@ -121,10 +133,11 @@ static mips_def_t mips_defs[] =
                    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
                    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
         .CP0_Config2 = MIPS_CONFIG2,
-        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
         .SYNCI_Step = 32,
         .CCRes = 2,
-        .Status_rw_bitmask = 0x3278FF17,
+        /* No DSP implemented. */
+        .CP0_Status_rw_bitmask = 0x1278FF17,
     },
     {
         .name = "24Kf",
@@ -134,13 +147,53 @@ static mips_def_t mips_defs[] =
                    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
                    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
         .CP0_Config2 = MIPS_CONFIG2,
-        .CP0_Config3 = MIPS_CONFIG3,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
         .SYNCI_Step = 32,
         .CCRes = 2,
-        .Status_rw_bitmask = 0x3678FF17,
+        /* No DSP implemented. */
+        .CP0_Status_rw_bitmask = 0x3678FF17,
         .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
                     (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
     },
+    {
+        .name = "34Kf",
+        .CP0_PRid = 0x00019500,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
+                   (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+                   (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt) | (1 << CP0C3_MT),
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        /* No DSP implemented. */
+        .CP0_Status_rw_bitmask = 0x3678FF17,
+        /* No DSP implemented. */
+        .CP0_TCStatus_rw_bitmask = (0 << CP0TCSt_TCU3) | (0 << CP0TCSt_TCU2) |
+                    (1 << CP0TCSt_TCU1) | (1 << CP0TCSt_TCU0) |
+                    (0 << CP0TCSt_TMX) | (1 << CP0TCSt_DT) |
+                    (1 << CP0TCSt_DA) | (1 << CP0TCSt_A) |
+                    (0x3 << CP0TCSt_TKSU) | (1 << CP0TCSt_IXMT) |
+                    (0xff << CP0TCSt_TASID),
+        .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
+                    (1 << FCR0_D) | (1 << FCR0_S) | (0x95 << FCR0_PRID),
+        .CP0_SRSCtl = (0xf << CP0SRSCtl_HSS),
+        .CP0_SRSConf0_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf0 = (1 << CP0SRSC0_M) | (0x3fe << CP0SRSC0_SRS3) |
+                    (0x3fe << CP0SRSC0_SRS2) | (0x3fe << CP0SRSC0_SRS1),
+        .CP0_SRSConf1_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf1 = (1 << CP0SRSC1_M) | (0x3fe << CP0SRSC1_SRS6) |
+                    (0x3fe << CP0SRSC1_SRS5) | (0x3fe << CP0SRSC1_SRS4),
+        .CP0_SRSConf2_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf2 = (1 << CP0SRSC2_M) | (0x3fe << CP0SRSC2_SRS9) |
+                    (0x3fe << CP0SRSC2_SRS8) | (0x3fe << CP0SRSC2_SRS7),
+        .CP0_SRSConf3_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf3 = (1 << CP0SRSC3_M) | (0x3fe << CP0SRSC3_SRS12) |
+                    (0x3fe << CP0SRSC3_SRS11) | (0x3fe << CP0SRSC3_SRS10),
+        .CP0_SRSConf4_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf4 = (0x3fe << CP0SRSC4_SRS15) |
+                    (0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13),
+    },
 #ifdef TARGET_MIPS64
     {
         .name = "R4000",
@@ -153,7 +206,7 @@ static mips_def_t mips_defs[] =
         .CP0_Config3 = MIPS_CONFIG3,
         .SYNCI_Step = 16,
         .CCRes = 2,
-        .Status_rw_bitmask = 0x3678FFFF,
+        .CP0_Status_rw_bitmask = 0x3678FFFF,
        /* The R4000 has a full 64bit FPU doesn't use the fcr0 bits. */
         .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV),
         .SEGBITS = 40,
@@ -170,7 +223,7 @@ static mips_def_t mips_defs[] =
         .CP0_Config3 = MIPS_CONFIG3,
         .SYNCI_Step = 32,
         .CCRes = 2,
-        .Status_rw_bitmask = 0x32F8FFFF,
+        .CP0_Status_rw_bitmask = 0x32F8FFFF,
         .SEGBITS = 42,
     },
     {
@@ -185,7 +238,7 @@ static mips_def_t mips_defs[] =
         .CP0_Config3 = MIPS_CONFIG3,
         .SYNCI_Step = 32,
         .CCRes = 2,
-        .Status_rw_bitmask = 0x36F8FFFF,
+        .CP0_Status_rw_bitmask = 0x36F8FFFF,
        /* The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */
         .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) |
                     (0x81 << FCR0_PRID) | (0x0 << FCR0_REV),
@@ -205,7 +258,7 @@ static mips_def_t mips_defs[] =
         .CP0_Config3 = MIPS_CONFIG3,
         .SYNCI_Step = 32,
         .CCRes = 2,
-        .Status_rw_bitmask = 0x36FBFFFF,
+        .CP0_Status_rw_bitmask = 0x36FBFFFF,
        /* The 20Kc has F64 / L / W but doesn't use the fcr0 bits. */
         .CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) |
                     (1 << FCR0_D) | (1 << FCR0_S) |
@@ -245,27 +298,88 @@ void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
 #ifndef CONFIG_USER_ONLY
 static void no_mmu_init (CPUMIPSState *env, mips_def_t *def)
 {
-    env->nb_tlb = 1;
-    env->map_address = &no_mmu_map_address;
+    env->tlb->nb_tlb = 1;
+    env->tlb->map_address = &no_mmu_map_address;
 }
 
 static void fixed_mmu_init (CPUMIPSState *env, mips_def_t *def)
 {
-    env->nb_tlb = 1;
-    env->map_address = &fixed_mmu_map_address;
+    env->tlb->nb_tlb = 1;
+    env->tlb->map_address = &fixed_mmu_map_address;
 }
 
 static void r4k_mmu_init (CPUMIPSState *env, mips_def_t *def)
 {
-    env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63);
-    env->map_address = &r4k_map_address;
-    env->do_tlbwi = r4k_do_tlbwi;
-    env->do_tlbwr = r4k_do_tlbwr;
-    env->do_tlbp = r4k_do_tlbp;
-    env->do_tlbr = r4k_do_tlbr;
+    env->tlb->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63);
+    env->tlb->map_address = &r4k_map_address;
+    env->tlb->do_tlbwi = r4k_do_tlbwi;
+    env->tlb->do_tlbwr = r4k_do_tlbwr;
+    env->tlb->do_tlbp = r4k_do_tlbp;
+    env->tlb->do_tlbr = r4k_do_tlbr;
+}
+
+static void mmu_init (CPUMIPSState *env, mips_def_t *def)
+{
+    env->tlb = qemu_mallocz(sizeof(CPUMIPSTLBContext));
+
+    /* There are more full-featured MMU variants in older MIPS CPUs,
+       R3000, R6000 and R8000 come to mind. If we ever support them,
+       this check will need to look up a different place than those
+       newfangled config registers. */
+    switch ((env->CP0_Config0 >> CP0C0_MT) & 3) {
+        case 0:
+            no_mmu_init(env, def);
+            break;
+        case 1:
+            r4k_mmu_init(env, def);
+            break;
+        case 3:
+            fixed_mmu_init(env, def);
+            break;
+        default:
+            cpu_abort(env, "MMU type not supported\n");
+    }
+    env->CP0_Random = env->tlb->nb_tlb - 1;
+    env->tlb->tlb_in_use = env->tlb->nb_tlb;
 }
 #endif /* CONFIG_USER_ONLY */
 
+static void fpu_init (CPUMIPSState *env, mips_def_t *def)
+{
+    env->fpu = qemu_mallocz(sizeof(CPUMIPSFPUContext));
+
+    env->fpu->fcr0 = def->CP1_fcr0;
+#ifdef CONFIG_USER_ONLY
+    if (env->CP0_Config1 & (1 << CP0C1_FP))
+        env->hflags |= MIPS_HFLAG_FPU;
+    if (env->fpu->fcr0 & (1 << FCR0_F64))
+        env->hflags |= MIPS_HFLAG_F64;
+#endif
+}
+
+static void mvp_init (CPUMIPSState *env, mips_def_t *def)
+{
+    env->mvp = qemu_mallocz(sizeof(CPUMIPSMVPContext));
+
+    /* MVPConf1 implemented, TLB sharable, no gating storage support,
+       programmable cache partitioning implemented, number of allocatable
+       and sharable TLB entries, MVP has allocatable TCs, 2 VPEs
+       implemented, 5 TCs implemented. */
+    env->mvp->CP0_MVPConf0 = (1 << CP0MVPC0_M) | (1 << CP0MVPC0_TLBS) |
+                             (0 << CP0MVPC0_GS) | (1 << CP0MVPC0_PCP) |
+                             (env->tlb->nb_tlb << CP0MVPC0_PTLBE) |
+// TODO: actually do 2 VPEs.
+//                             (1 << CP0MVPC0_TCA) | (0x1 << CP0MVPC0_PVPE) |
+//                             (0x04 << CP0MVPC0_PTC);
+                             (1 << CP0MVPC0_TCA) | (0x0 << CP0MVPC0_PVPE) |
+                             (0x04 << CP0MVPC0_PTC);
+    /* Allocatable CP1 have media extensions, allocatable CP1 have FP support,
+       no UDI implemented, no CP2 implemented, 1 CP1 implemented. */
+    env->mvp->CP0_MVPConf1 = (1 << CP0MVPC1_CIM) | (1 << CP0MVPC1_CIF) |
+                             (0x0 << CP0MVPC1_PCX) | (0x0 << CP0MVPC1_PCP2) |
+                             (0x1 << CP0MVPC1_PCP1);
+}
+
 int cpu_mips_register (CPUMIPSState *env, mips_def_t *def)
 {
     if (!def)
@@ -285,8 +399,9 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def)
     env->CP0_Config7 = def->CP0_Config7;
     env->SYNCI_Step = def->SYNCI_Step;
     env->CCRes = def->CCRes;
-    env->Status_rw_bitmask = def->Status_rw_bitmask;
-    env->fcr0 = def->CP1_fcr0;
+    env->CP0_Status_rw_bitmask = def->CP0_Status_rw_bitmask;
+    env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask;
+    env->CP0_SRSCtl = def->CP0_SRSCtl;
 #ifdef TARGET_MIPS64
     if ((env->CP0_Config0 & (0x3 << CP0C0_AT)))
     {
@@ -298,31 +413,21 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def)
         env->SEGMask = 0xFFFFFFFF;
     }
 #endif
-#ifdef CONFIG_USER_ONLY
-    if (env->CP0_Config1 & (1 << CP0C1_FP))
-        env->hflags |= MIPS_HFLAG_FPU;
-    if (env->fcr0 & (1 << FCR0_F64))
-        env->hflags |= MIPS_HFLAG_F64;
-#else
-    /* There are more full-featured MMU variants in older MIPS CPUs,
-       R3000, R6000 and R8000 come to mind. If we ever support them,
-       this check will need to look up a different place than those
-       newfangled config registers. */
-    switch ((env->CP0_Config0 >> CP0C0_MT) & 3) {
-        case 0:
-            no_mmu_init(env, def);
-            break;
-        case 1:
-            r4k_mmu_init(env, def);
-            break;
-        case 3:
-            fixed_mmu_init(env, def);
-            break;
-        default:
-            cpu_abort(env, "MMU type not supported\n");
-    }
-    env->CP0_Random = env->nb_tlb - 1;
-    env->tlb_in_use = env->nb_tlb;
-#endif /* CONFIG_USER_ONLY */
+    env->CP0_SRSConf0_rw_bitmask = def->CP0_SRSConf0_rw_bitmask;
+    env->CP0_SRSConf0 = def->CP0_SRSConf0;
+    env->CP0_SRSConf1_rw_bitmask = def->CP0_SRSConf1_rw_bitmask;
+    env->CP0_SRSConf1 = def->CP0_SRSConf1;
+    env->CP0_SRSConf2_rw_bitmask = def->CP0_SRSConf2_rw_bitmask;
+    env->CP0_SRSConf2 = def->CP0_SRSConf2;
+    env->CP0_SRSConf3_rw_bitmask = def->CP0_SRSConf3_rw_bitmask;
+    env->CP0_SRSConf3 = def->CP0_SRSConf3;
+    env->CP0_SRSConf4_rw_bitmask = def->CP0_SRSConf4_rw_bitmask;
+    env->CP0_SRSConf4 = def->CP0_SRSConf4;
+
+#ifndef CONFIG_USER_ONLY
+    mmu_init(env, def);
+#endif
+    fpu_init(env, def);
+    mvp_init(env, def);
     return 0;
 }
index 491b3b3d338d4b3ef3489c9769e384aa8b13a794..bd5286f2a1969ee1c7dcf88deac12fba774a5824 100644 (file)
@@ -305,7 +305,7 @@ int cpu_restore_state(TranslationBlock *tb,
 #elif defined(TARGET_M68K)
     env->pc = gen_opc_pc[j];
 #elif defined(TARGET_MIPS)
-    env->PC = gen_opc_pc[j];
+    env->PC[env->current_tc] = gen_opc_pc[j];
     env->hflags &= ~MIPS_HFLAG_BMASK;
     env->hflags |= gen_opc_hflags[j];
 #elif defined(TARGET_ALPHA)