qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 6/6] A cumulative MIPS patchset


From: Thiemo Seufer
Subject: [Qemu-devel] [PATCH 6/6] A cumulative MIPS patchset
Date: Tue, 21 Nov 2006 15:22:58 -0000
User-agent: Mutt/1.5.13 (2006-08-11)

Hello All,

this patch adds support for all mandatory MIPS32R2 instructions,
rationalizes the instruction decoding to check always 32-bit words,
reduces the number of magic constants in the code, adds a few bits
which make eventually implementation of MIPS64 support and optional
MIPS32 features easier.

The emulated CPU still identifies itself as a MIPS32(R1) 4Kc.
Currently it doesn't throw a RI exception for R2 instructions, this
is useful for Linux userland emulation, and also follows the current
policy which doesn't distinguish between MIPS32R1 instructions and
those of earlier ISAs.


Thiemo


Index: qemu-work/target-mips/cpu.h
===================================================================
--- qemu-work.orig/target-mips/cpu.h    2006-11-21 13:42:28.000000000 +0000
+++ qemu-work/target-mips/cpu.h 2006-11-21 13:42:52.000000000 +0000
@@ -99,14 +99,16 @@
 #endif
     uint32_t CP0_index;
     uint32_t CP0_random;
-    uint32_t CP0_EntryLo0;
-    uint32_t CP0_EntryLo1;
-    uint32_t CP0_Context;
+    uint64_t CP0_EntryLo0;
+    uint64_t CP0_EntryLo1;
+    uint64_t CP0_Context;
     uint32_t CP0_PageMask;
+    uint32_t CP0_PageGrain;
     uint32_t CP0_Wired;
+    uint32_t CP0_HWREna;
     uint32_t CP0_BadVAddr;
     uint32_t CP0_Count;
-    uint32_t CP0_EntryHi;
+    uint64_t CP0_EntryHi;
     uint32_t CP0_Compare;
     uint32_t CP0_Status;
 #define CP0St_CU3   31
@@ -116,19 +118,36 @@
 #define CP0St_RP    27
 #define CP0St_FR    26
 #define CP0St_RE    25
+#define CP0St_MX    24
+#define CP0St_PX    23
 #define CP0St_BEV   22
 #define CP0St_TS    21
 #define CP0St_SR    20
 #define CP0St_NMI   19
 #define CP0St_IM    8
+#define CP0St_KX    7
+#define CP0St_SX    6
+#define CP0St_UX    5
 #define CP0St_UM    4
+#define CP0St_R0    3
 #define CP0St_ERL   2
 #define CP0St_EXL   1
 #define CP0St_IE    0
+    uint32_t CP0_IntCtl;
+    uint32_t CP0_SRSCtl;
     uint32_t CP0_Cause;
+#define CP0Ca_BD   31
+#define CP0Ca_TI   30
+#define CP0Ca_CE   28
+#define CP0Ca_DC   27
+#define CP0Ca_PCI  26
 #define CP0Ca_IV   23
+#define CP0Ca_WP   22
+#define CP0Ca_IP    8
+#define CP0Ca_EC    2
     uint32_t CP0_EPC;
     uint32_t CP0_PRid;
+    uint32_t CP0_EBase;
     uint32_t CP0_Config0;
 #define CP0C0_M    31
 #define CP0C0_K23  28
@@ -140,8 +159,10 @@
 #define CP0C0_AT   13
 #define CP0C0_AR   10
 #define CP0C0_MT   7
+#define CP0C0_VI   3
 #define CP0C0_K0   0
     uint32_t CP0_Config1;
+#define CP0C1_M    31
 #define CP0C1_MMU  25
 #define CP0C1_IS   22
 #define CP0C1_IL   19
@@ -149,14 +170,38 @@
 #define CP0C1_DS   13
 #define CP0C1_DL   10
 #define CP0C1_DA   7
+#define CP0C1_C2   6
+#define CP0C1_MD   5
 #define CP0C1_PC   4
 #define CP0C1_WR   3
 #define CP0C1_CA   2
 #define CP0C1_EP   1
 #define CP0C1_FP   0
+    uint32_t CP0_Config2;
+#define CP0C2_M    31
+#define CP0C2_TU   28
+#define CP0C2_TS   24
+#define CP0C2_TL   20
+#define CP0C2_TA   16
+#define CP0C2_SU   12
+#define CP0C2_SS   8
+#define CP0C2_SL   4
+#define CP0C2_SA   0
+    uint32_t CP0_Config3;
+#define CP0C3_M    31
+#define CP0C3_DSPP 10
+#define CP0C3_LPA  7
+#define CP0C3_VEIC 6
+#define CP0C3_VInt 5
+#define CP0C3_SP   4
+#define CP0C3_MT   2
+#define CP0C3_SM   1
+#define CP0C3_TL   0
     uint32_t CP0_LLAddr;
     uint32_t CP0_WatchLo;
     uint32_t CP0_WatchHi;
+    uint32_t CP0_XContext;
+    uint32_t CP0_Framemask;
     uint32_t CP0_Debug;
 #define CPDB_DBD   31
 #define CP0DB_DM   30
@@ -177,8 +222,11 @@
 #define CP0DB_DBp  1
 #define CP0DB_DSS  0
     uint32_t CP0_DEPC;
+    uint32_t CP0_Performance0;
     uint32_t CP0_TagLo;
     uint32_t CP0_DataLo;
+    uint32_t CP0_TagHi;
+    uint32_t CP0_DataHi;
     uint32_t CP0_ErrorEPC;
     uint32_t CP0_DESAVE;
     /* Qemu */
@@ -211,6 +259,9 @@
 
     int halted; /* TRUE if the CPU is in suspend state */
 
+    int SYNCI_Step; /* Address step size for SYNCI */
+    int CCRes; /* Cycle count resolution/divisor */
+
     CPU_COMMON
 
     int ram_size;
Index: qemu-work/target-mips/exec.h
===================================================================
--- qemu-work.orig/target-mips/exec.h   2006-11-21 13:42:28.000000000 +0000
+++ qemu-work/target-mips/exec.h        2006-11-21 14:01:25.000000000 +0000
@@ -68,6 +68,7 @@
 #endif
 void do_mfc0_random(void);
 void do_mfc0_count(void);
+void do_mtc0_entryhi(uint32_t in);
 void do_mtc0_status_debug(uint32_t old, uint32_t val);
 void do_mtc0_status_irqraise_debug(void);
 void do_tlbwi (void);
Index: qemu-work/target-mips/helper.c
===================================================================
--- qemu-work.orig/target-mips/helper.c 2006-11-21 13:42:28.000000000 +0000
+++ qemu-work/target-mips/helper.c      2006-11-21 13:42:52.000000000 +0000
@@ -302,15 +302,9 @@
 #endif
         env->CP0_Wired = 0;
         env->CP0_Config0 = MIPS_CONFIG0;
-#if defined (MIPS_CONFIG1)
         env->CP0_Config1 = MIPS_CONFIG1;
-#endif
-#if defined (MIPS_CONFIG2)
         env->CP0_Config2 = MIPS_CONFIG2;
-#endif
-#if defined (MIPS_CONFIG3)
         env->CP0_Config3 = MIPS_CONFIG3;
-#endif
         env->CP0_WatchLo = 0;
         env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
         goto set_error_EPC;
Index: qemu-work/target-mips/mips-defs.h
===================================================================
--- qemu-work.orig/target-mips/mips-defs.h      2006-11-21 13:42:28.000000000 
+0000
+++ qemu-work/target-mips/mips-defs.h   2006-11-21 13:42:52.000000000 +0000
@@ -29,26 +29,44 @@
  * Define a major version 1, minor version 0.
  */
 #define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0)
-/* Have config1, uses TLB */
-#define MIPS_CONFIG0_1                                          \
-((1 << CP0C0_M) | (0 << CP0C0_K23) | (0 << CP0C0_KU) |          \
- (1 << CP0C0_MT) | (2 << CP0C0_K0))
+  /* Have config1, is MIPS32R1, uses TLB, no virtual icache,
+     uncached coherency */
+#define MIPS_CONFIG0_1                                            \
+  ((1 << CP0C0_M) | (0x0 << CP0C0_K23) | (0x0 << CP0C0_KU) |      \
+   (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) | (0x1 << CP0C0_MT) |    \
+   (0x2 << CP0C0_K0))
 #ifdef TARGET_WORDS_BIGENDIAN
 #define MIPS_CONFIG0 (MIPS_CONFIG0_1 | (1 << CP0C0_BE))
 #else
 #define MIPS_CONFIG0 MIPS_CONFIG0_1
 #endif
-/* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache,
- * 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
- * no performance counters, watch registers present, no code compression,
- * EJTAG present, FPU enable bit depending on MIPS_USES_FPU
- */
-#define MIPS_CONFIG1                                            \
-((15 << CP0C1_MMU) |                                            \
- (0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \
- (0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \
- (0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) |          \
- (1 << CP0C1_EP) | (MIPS_USES_FPU << CP0C1_FP))
+/* Have config2, 16 TLB entries, 64 sets Icache, 16 bytes Icache line,
+   2-way Icache, 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
+   no coprocessor2 attached, no MDMX support attached,
+   no performance counters, watch registers present,
+   no code compression, EJTAG present, FPU enable bit depending on
+   MIPS_USES_FPU */
+#define MIPS_CONFIG1_1                                            \
+((1 << CP0C1_M) | ((MIPS_TLB_NB - 1) << CP0C1_MMU) |              \
+ (0x0 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x1 << CP0C1_IA) |      \
+ (0x0 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x1 << CP0C1_DA) |      \
+ (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) |            \
+ (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP))
+#ifdef MIPS_USES_FPU
+#define MIPS_CONFIG1  (MIPS_CONFIG1_1 | (1 << CP0C1_FP))
+#else
+#define MIPS_CONFIG1  (MIPS_CONFIG1_1 | (0 << CP0C1_FP))
+#endif
+/* Have config3, no tertiary/secondary caches implemented */
+#define MIPS_CONFIG2                                              \
+((1 << CP0C2_M))
+/* 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 */
+#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))
 #elif (MIPS_CPU == MIPS_R4Kp)
 /* 32 bits target */
 #define TARGET_LONG_BITS 32
@@ -60,7 +78,7 @@
 #define MIPS_USES_R4K_FPM
 #else
 #error "MIPS CPU not defined"
-/* Remainder for other flags */
+/* Reminder for other flags */
 //#define TARGET_MIPS64
 //#define MIPS_USES_FPU
 #endif
Index: qemu-work/target-mips/op.c
===================================================================
--- qemu-work.orig/target-mips/op.c     2006-11-21 13:42:28.000000000 +0000
+++ qemu-work/target-mips/op.c  2006-11-21 13:58:05.000000000 +0000
@@ -437,6 +437,18 @@
     RETURN();
 }
 
+void op_rotr (void)
+{
+    target_ulong tmp;
+
+    if (T1) {
+       tmp = T0 << (0x20 - T1);
+       T0 = (T0 >> T1) | tmp;
+    } else
+       T0 = T1;
+    RETURN();
+}
+
 void op_sllv (void)
 {
     T0 = T1 << (T0 & 0x1F);
@@ -455,6 +467,19 @@
     RETURN();
 }
 
+void op_rotrv (void)
+{
+    target_ulong tmp;
+
+    T0 &= 0x1F;
+    if (T0) {
+       tmp = T1 << (0x20 - T0);
+       T0 = (T1 >> T0) | tmp;
+    } else
+       T0 = T1;
+    RETURN();
+}
+
 void op_clo (void)
 {
     int n;
@@ -602,6 +627,20 @@
     RETURN();
 }
 
+void op_movf (void)
+{
+    if (!(env->fcr31 & PARAM1))
+        env->gpr[PARAM2] = env->gpr[PARAM3];
+    RETURN();
+}
+
+void op_movt (void)
+{
+    if (env->fcr31 & PARAM1)
+        env->gpr[PARAM2] = env->gpr[PARAM3];
+    RETURN();
+}
+
 /* Tests */
 #define OP_COND(name, cond) \
 void glue(op_, name) (void) \
@@ -625,28 +664,32 @@
 OP_COND(lez, (int32_t)T0 <= 0);
 OP_COND(ltz, (int32_t)T0 < 0);
 
-/* Branchs */
+/* Branches */
 //#undef USE_DIRECT_JUMP
 
 void OPPROTO op_goto_tb0(void)
 {
     GOTO_TB(op_goto_tb0, PARAM1, 0);
+    RETURN();
 }
 
 void OPPROTO op_goto_tb1(void)
 {
     GOTO_TB(op_goto_tb1, PARAM1, 1);
+    RETURN();
 }
 
 /* Branch to register */
 void op_save_breg_target (void)
 {
     env->btarget = T2;
+    RETURN();
 }
 
 void op_restore_breg_target (void)
 {
     T2 = env->btarget;
+    RETURN();
 }
 
 void op_breg (void)
@@ -724,12 +767,24 @@
     RETURN();
 }
 
+void op_mfc0_pagegrain (void)
+{
+    T0 = env->CP0_PageGrain;
+    RETURN();
+}
+
 void op_mfc0_wired (void)
 {
     T0 = env->CP0_Wired;
     RETURN();
 }
 
+void op_mfc0_hwrena (void)
+{
+    T0 = env->CP0_HWREna;
+    RETURN();
+}
+
 void op_mfc0_badvaddr (void)
 {
     T0 = env->CP0_BadVAddr;
@@ -766,6 +821,18 @@
     RETURN();
 }
 
+void op_mfc0_intctl (void)
+{
+    T0 = env->CP0_IntCtl;
+    RETURN();
+}
+
+void op_mfc0_srsctl (void)
+{
+    T0 = env->CP0_SRSCtl;
+    RETURN();
+}
+
 void op_mfc0_cause (void)
 {
     T0 = env->CP0_Cause;
@@ -784,6 +851,12 @@
     RETURN();
 }
 
+void op_mfc0_ebase (void)
+{
+    T0 = env->CP0_EBase;
+    RETURN();
+}
+
 void op_mfc0_config0 (void)
 {
     T0 = env->CP0_Config0;
@@ -796,24 +869,48 @@
     RETURN();
 }
 
+void op_mfc0_config2 (void)
+{
+    T0 = env->CP0_Config2;
+    RETURN();
+}
+
+void op_mfc0_config3 (void)
+{
+    T0 = env->CP0_Config3;
+    RETURN();
+}
+
 void op_mfc0_lladdr (void)
 {
     T0 = env->CP0_LLAddr >> 4;
     RETURN();
 }
 
-void op_mfc0_watchlo (void)
+void op_mfc0_watchlo0 (void)
 {
     T0 = env->CP0_WatchLo;
     RETURN();
 }
 
-void op_mfc0_watchhi (void)
+void op_mfc0_watchhi0 (void)
 {
     T0 = env->CP0_WatchHi;
     RETURN();
 }
 
+void op_mfc0_xcontext (void)
+{
+    T0 = env->CP0_XContext;
+    RETURN();
+}
+
+void op_mfc0_framemask (void)
+{
+    T0 = env->CP0_Framemask;
+    RETURN();
+}
+
 void op_mfc0_debug (void)
 {
     T0 = env->CP0_Debug;
@@ -828,6 +925,12 @@
     RETURN();
 }
 
+void op_mfc0_performance0 (void)
+{
+    T0 = env->CP0_Performance0;
+    RETURN();
+}
+
 void op_mfc0_taglo (void)
 {
     T0 = env->CP0_TagLo;
@@ -840,6 +943,18 @@
     RETURN();
 }
 
+void op_mfc0_taghi (void)
+{
+    T0 = env->CP0_TagHi;
+    RETURN();
+}
+
+void op_mfc0_datahi (void)
+{
+    T0 = env->CP0_DataHi;
+    RETURN();
+}
+
 void op_mfc0_errorepc (void)
 {
     T0 = env->CP0_ErrorEPC;
@@ -854,37 +969,57 @@
 
 void op_mtc0_index (void)
 {
-    env->CP0_index = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
+    env->CP0_index = (env->CP0_index & 0x80000000) | (T0 & (MIPS_TLB_NB - 1));
     RETURN();
 }
 
 void op_mtc0_entrylo0 (void)
 {
-    env->CP0_EntryLo0 = T0 & 0x3FFFFFFF;
+    /* Large physaddr not implemented */
+    /* 1k pages not implemented */
+    env->CP0_EntryLo0 = T0 & 0x3FFFFFFFUL;
     RETURN();
 }
 
 void op_mtc0_entrylo1 (void)
 {
-    env->CP0_EntryLo1 = T0 & 0x3FFFFFFF;
+    /* Large physaddr not implemented */
+    /* 1k pages not implemented */
+    env->CP0_EntryLo1 = T0 & 0x3FFFFFFFUL;
     RETURN();
 }
 
 void op_mtc0_context (void)
 {
-    env->CP0_Context = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0);
+    env->CP0_Context = (env->CP0_Context & ~0x007FFFFF) | (T0 & 0x007FFFF0);
     RETURN();
 }
 
 void op_mtc0_pagemask (void)
 {
-    env->CP0_PageMask = T0 & 0x01FFE000;
+    /* 1k pages not implemented */
+    env->CP0_PageMask = T0 & 0x1FFFE000;
+    RETURN();
+}
+
+void op_mtc0_pagegrain (void)
+{
+    /* SmartMIPS not implemented */
+    /* Large physaddr not implemented */
+    /* 1k pages not implemented */
+    env->CP0_PageGrain = 0;
     RETURN();
 }
 
 void op_mtc0_wired (void)
 {
-    env->CP0_Wired = T0 & 0x0000000F;
+    env->CP0_Wired = T0 & (MIPS_TLB_NB - 1);
+    RETURN();
+}
+
+void op_mtc0_hwrena (void)
+{
+    env->CP0_HWREna = T0 & 0x0000000F;
     RETURN();
 }
 
@@ -950,6 +1085,20 @@
     RETURN();
 }
 
+void op_mtc0_intctl (void)
+{
+    /* vectored interrupts not implemented */
+    env->CP0_IntCtl = 0;
+    RETURN();
+}
+
+void op_mtc0_srsctl (void)
+{
+    /* shadow registers not implemented */
+    env->CP0_SRSCtl = 0;
+    RETURN();
+}
+
 void op_mtc0_cause (void)
 {
     uint32_t val, old;
@@ -960,7 +1109,6 @@
 #if 0
     {
         int i, mask;
-
        /* Check if we ever asserted a software IRQ */
         for (i = 0; i < 2; i++) {
             mask = 0x100 << i;
@@ -978,28 +1126,56 @@
     RETURN();
 }
 
+void op_mtc0_ebase (void)
+{
+    /* vectored interrupts not implemented */
+    /* Multi-CPU not implemented */
+    env->CP0_EBase = 0x80000000 | (T0 & 0x3FFFF000);
+    RETURN();
+}
+
 void op_mtc0_config0 (void)
 {
 #if defined(MIPS_USES_R4K_TLB)
-    env->CP0_Config0 = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
+     /* Fixed mapping MMU not implemented */
+    env->CP0_Config0 = (env->CP0_Config0 & 0x8017FF88) | (T0 & 0x00000001);
 #else
-    env->CP0_Config0 = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
+    env->CP0_Config0 = (env->CP0_Config0 & 0xFE17FF88) | (T0 & 0x00000001);
 #endif
     RETURN();
 }
 
-void op_mtc0_watchlo (void)
+void op_mtc0_config2 (void)
+{
+    /* tertiary/secondary caches not implemented */
+    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
+    RETURN();
+}
+
+void op_mtc0_watchlo0 (void)
 {
     env->CP0_WatchLo = T0;
     RETURN();
 }
 
-void op_mtc0_watchhi (void)
+void op_mtc0_watchhi0 (void)
 {
     env->CP0_WatchHi = T0 & 0x40FF0FF8;
     RETURN();
 }
 
+void op_mtc0_xcontext (void)
+{
+    env->CP0_XContext = T0; /* XXX */
+    RETURN();
+}
+
+void op_mtc0_framemask (void)
+{
+    env->CP0_Framemask = T0; /* XXX */
+    RETURN();
+}
+
 void op_mtc0_debug (void)
 {
     env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
@@ -1016,12 +1192,36 @@
     RETURN();
 }
 
+void op_mtc0_performance0 (void)
+{
+    env->CP0_Performance0 = T0; /* XXX */
+    RETURN();
+}
+
 void op_mtc0_taglo (void)
 {
     env->CP0_TagLo = T0 & 0xFFFFFCF6;
     RETURN();
 }
 
+void op_mtc0_datalo (void)
+{
+    env->CP0_DataLo = T0; /* XXX */
+    RETURN();
+}
+
+void op_mtc0_taghi (void)
+{
+    env->CP0_TagHi = T0; /* XXX */
+    RETURN();
+}
+
+void op_mtc0_datahi (void)
+{
+    env->CP0_DataHi = T0; /* XXX */
+    RETURN();
+}
+
 void op_mtc0_errorepc (void)
 {
     env->CP0_ErrorEPC = T0;
@@ -1422,6 +1622,42 @@
 void op_pmon (void)
 {
     CALL_FROM_TB1(do_pmon, PARAM1);
+    RETURN();
+}
+
+void op_di (void)
+{
+    uint32_t val;
+
+    T0 = env->CP0_Status;
+    val = T0 & ~(1 << CP0St_IE);
+    if (val != T0) {
+        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+        env->CP0_Status = val;
+    }
+    RETURN();
+}
+
+void op_ei (void)
+{
+    uint32_t val;
+
+    T0 = env->CP0_Status;
+    val = T0 | (1 << CP0St_IE);
+    if (val != T0) {
+       const uint32_t mask = 0x0000FF00;
+
+       env->CP0_Status = val;
+       if (!(env->hflags & MIPS_HFLAG_EXL) &&
+           !(env->hflags & MIPS_HFLAG_ERL) &&
+           !(env->hflags & MIPS_HFLAG_DM) &&
+           (env->CP0_Status & env->CP0_Cause & mask)) {
+               env->interrupt_request |= CPU_INTERRUPT_HARD;
+               if (logfile)
+                   CALL_FROM_TB0(do_mtc0_status_irqraise_debug);
+       }
+    }
+    RETURN();
 }
 
 void op_trap (void)
@@ -1434,12 +1670,14 @@
 
 void op_debug (void)
 {
-  CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG);
+    CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG);
+    RETURN();
 }
 
 void op_set_lladdr (void)
 {
     env->CP0_LLAddr = T2;
+    RETURN();
 }
 
 void debug_eret (void);
@@ -1456,12 +1694,50 @@
        env->CP0_Status &= ~(1 << CP0St_EXL);
     }
     env->CP0_LLAddr = 1;
+    RETURN();
 }
 
 void op_deret (void)
 {
     CALL_FROM_TB0(debug_eret);
     env->PC = env->CP0_DEPC;
+    RETURN();
+}
+
+void op_rdhwr_cpunum(void)
+{
+    if (env->CP0_HWREna & (1 << 0))
+       T0 = env->CP0_EBase & 0x2ff;
+    else
+       CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+    RETURN();
+}
+
+void op_rdhwr_synci_step(void)
+{
+    if (env->CP0_HWREna & (1 << 1))
+       T0 = env->SYNCI_Step;
+    else
+       CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+    RETURN();
+}
+
+void op_rdhwr_cc(void)
+{
+    if (env->CP0_HWREna & (1 << 2))
+       T0 = env->CP0_Count;
+    else
+       CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+    RETURN();
+}
+
+void op_rdhwr_ccres(void)
+{
+    if (env->CP0_HWREna & (1 << 3))
+       T0 = env->CCRes;
+    else
+       CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+    RETURN();
 }
 
 void op_save_state (void)
@@ -1491,10 +1767,119 @@
 void op_exit_tb (void)
 {
     EXIT_TB();
+    RETURN();
 }
 
 void op_wait (void)
 {
     env->halted = 1;
     CALL_FROM_TB1(do_raise_exception, EXCP_HLT);
+    RETURN();
+}
+
+/* Bitfield operations. */
+void op_ext(void)
+{
+    unsigned int pos = PARAM1;
+    unsigned int size = PARAM2 % (0x20 - pos);
+
+    T0 = (T1 >> pos) & ((1 << size) - 1);
+    RETURN();
+}
+
+void op_dextm(void)
+{
+    unsigned int pos = PARAM1;
+    unsigned int size = PARAM2 % (0x40 - pos);
+
+    T0 = (T1 >> pos) & ((1 << size) - 1);
+    RETURN();
+}
+
+void op_dextu(void)
+{
+    unsigned int pos = PARAM1 + 0x20;
+    unsigned int size = PARAM2 % (0x40 - pos);
+
+    T0 = (T1 >> pos) & ((1 << size) - 1);
+    RETURN();
+}
+
+void op_dext(void)
+{
+    unsigned int pos = PARAM1;
+    unsigned int size = PARAM2 % 0x20;
+
+    T0 = (T1 >> pos) & ((1 << size) - 1);
+    RETURN();
+}
+
+void op_ins(void)
+{
+    unsigned int pos = PARAM1;
+    unsigned int size = PARAM2 % (0x20 - pos);
+    uint32_t mask = ((1 << size) - 1) << pos;
+
+    T0 = (T2 & ~mask) | ((T1 << pos) & mask);
+    RETURN();
+}
+
+void op_dinsm(void)
+{
+    unsigned int pos = PARAM1;
+    unsigned int size = PARAM2 % (0x40 - pos);
+    target_ulong mask = ((1 << size) - 1) << pos;
+
+    T0 = (T2 & ~mask) | ((T1 << pos) & mask);
+    RETURN();
+}
+
+void op_dinsu(void)
+{
+    unsigned int pos = PARAM1 + 0x20;
+    unsigned int size = PARAM2 % (0x40 - pos);
+    target_ulong mask = ((1 << size) - 1) << pos;
+
+    T0 = (T2 & ~mask) | ((T1 << pos) & mask);
+    RETURN();
+}
+
+void op_dins(void)
+{
+    unsigned int pos = PARAM1;
+    unsigned int size = PARAM2;
+    target_ulong mask = ((1 << size) - 1) << pos;
+
+    T0 = (T2 & ~mask) | ((T1 << pos) & mask);
+    RETURN();
+}
+
+void op_wsbh(void)
+{
+    T0 = ((T1 << 8) & ~0x00FF00FF) | ((T1 >> 8) & 0x00FF00FF);
+    RETURN();
+}
+
+void op_dsbh(void)
+{
+    T0 = ((T1 << 8) & ~0x00FF00FF00FF00FFULL) | ((T1 >> 8) & 
0x00FF00FF00FF00FFULL);
+    RETURN();
+}
+
+void op_dshd(void)
+{
+    T0 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 
0x0000FFFF0000FFFFULL);
+    RETURN();
+}
+
+void op_seb(void)
+{
+    T0 = ((T1 & 0xFF) ^ 0x80) - 0x80;
+    RETURN();
+}
+
+void op_seh(void)
+{
+    T0 = ((T1 & 0xFFFF) ^ 0x8000) - 0x8000;
+    RETURN();
 }
Index: qemu-work/target-mips/op_helper.c
===================================================================
--- qemu-work.orig/target-mips/op_helper.c      2006-11-21 13:42:28.000000000 
+0000
+++ qemu-work/target-mips/op_helper.c   2006-11-21 13:42:52.000000000 +0000
@@ -152,14 +152,19 @@
     cpu_abort(env, "mtc0 compare\n");
 }
 
+void do_mtc0_entryhi (uint32_t val)
+{
+    cpu_abort(env, "mtc0 entryhi\n");
+}
+
 void do_mtc0_status_debug(uint32_t old, uint32_t val)
 {
-    cpu_abort(env, "mtc0 status\n");
+    cpu_abort(env, "mtc0 status debug\n");
 }
 
-void do_mtc0_status_irqraise_debug(void)
+void do_mtc0_status_irqraise_debug (void)
 {
-    cpu_abort(env, "mtc0 status\n");
+    cpu_abort(env, "mtc0 status irqraise debug\n");
 }
 
 void do_tlbwi (void)
@@ -200,6 +205,19 @@
     T0 = cpu_mips_get_count(env);
 }
 
+void do_mtc0_entryhi (uint32_t in)
+{
+    uint32_t old;
+
+    /* 1k pages not implemented */
+    /* Ignore MIPS64 TLB for now */
+    old = env->CP0_EntryHi;
+    env->CP0_EntryHi = in & 0xFFFFE0FF;
+    /* If the ASID changes, flush qemu's TLB.  */
+    if ((old & 0xFF) != (in & 0xFF))
+        cpu_mips_tlb_flush(env, 1);
+}
+
 void do_mtc0_status_debug(uint32_t old, uint32_t val)
 {
     const uint32_t mask = 0x0000FF00;
Index: qemu-work/target-mips/translate.c
===================================================================
--- qemu-work.orig/target-mips/translate.c      2006-11-21 13:42:28.000000000 
+0000
+++ qemu-work/target-mips/translate.c   2006-11-21 14:01:43.000000000 +0000
@@ -50,184 +50,313 @@
 
 #include "gen-op.h"
 
-/* MIPS opcodes */
-#define EXT_SPECIAL  0x100
-#define EXT_SPECIAL2 0x200
-#define EXT_REGIMM   0x300
-#define EXT_CP0      0x400
-#define EXT_CP1      0x500
-#define EXT_CP2      0x600
-#define EXT_CP3      0x700
+/* MIPS major opcodes */
+#define MASK_OP_MAJOR(op)  (op & (0x3F << 26))
 
 enum {
     /* indirect opcode tables */
-    OPC_SPECIAL  = 0x00,
-    OPC_BREGIMM  = 0x01,
-    OPC_CP0      = 0x10,
-    OPC_CP1      = 0x11,
-    OPC_CP2      = 0x12,
-    OPC_CP3      = 0x13,
-    OPC_SPECIAL2 = 0x1C,
+    OPC_SPECIAL  = (0x00 << 26),
+    OPC_REGIMM   = (0x01 << 26),
+    OPC_CP0      = (0x10 << 26),
+    OPC_CP1      = (0x11 << 26),
+    OPC_CP2      = (0x12 << 26),
+    OPC_CP3      = (0x13 << 26),
+    OPC_SPECIAL2 = (0x1C << 26),
+    OPC_SPECIAL3 = (0x1F << 26),
     /* arithmetic with immediate */
-    OPC_ADDI     = 0x08,
-    OPC_ADDIU    = 0x09,
-    OPC_SLTI     = 0x0A,
-    OPC_SLTIU    = 0x0B,
-    OPC_ANDI     = 0x0C,
-    OPC_ORI      = 0x0D,
-    OPC_XORI     = 0x0E,
-    OPC_LUI      = 0x0F,
+    OPC_ADDI     = (0x08 << 26),
+    OPC_ADDIU    = (0x09 << 26),
+    OPC_SLTI     = (0x0A << 26),
+    OPC_SLTIU    = (0x0B << 26),
+    OPC_ANDI     = (0x0C << 26),
+    OPC_ORI      = (0x0D << 26),
+    OPC_XORI     = (0x0E << 26),
+    OPC_LUI      = (0x0F << 26),
+    OPC_DADDI    = (0x18 << 26),
+    OPC_DADDIU   = (0x19 << 26),
     /* Jump and branches */
-    OPC_J        = 0x02,
-    OPC_JAL      = 0x03,
-    OPC_BEQ      = 0x04,  /* Unconditional if rs = rt = 0 (B) */
-    OPC_BEQL     = 0x14,
-    OPC_BNE      = 0x05,
-    OPC_BNEL     = 0x15,
-    OPC_BLEZ     = 0x06,
-    OPC_BLEZL    = 0x16,
-    OPC_BGTZ     = 0x07,
-    OPC_BGTZL    = 0x17,
-    OPC_JALX     = 0x1D,  /* MIPS 16 only */
+    OPC_J        = (0x02 << 26),
+    OPC_JAL      = (0x03 << 26),
+    OPC_BEQ      = (0x04 << 26),  /* Unconditional if rs = rt = 0 (B) */
+    OPC_BEQL     = (0x14 << 26),
+    OPC_BNE      = (0x05 << 26),
+    OPC_BNEL     = (0x15 << 26),
+    OPC_BLEZ     = (0x06 << 26),
+    OPC_BLEZL    = (0x16 << 26),
+    OPC_BGTZ     = (0x07 << 26),
+    OPC_BGTZL    = (0x17 << 26),
+    OPC_JALX     = (0x1D << 26),  /* MIPS 16 only */
     /* Load and stores */
-    OPC_LB       = 0x20,
-    OPC_LH       = 0x21,
-    OPC_LWL      = 0x22,
-    OPC_LW       = 0x23,
-    OPC_LBU      = 0x24,
-    OPC_LHU      = 0x25,
-    OPC_LWR      = 0x26,
-    OPC_LWU      = 0x27,
-    OPC_SB       = 0x28,
-    OPC_SH       = 0x29,
-    OPC_SWL      = 0x2A,
-    OPC_SW       = 0x2B,
-    OPC_SWR      = 0x2E,
-    OPC_LL       = 0x30,
-    OPC_SC       = 0x38,
+    OPC_LDL      = (0x1A << 26),
+    OPC_LDR      = (0x1B << 26),
+    OPC_LB       = (0x20 << 26),
+    OPC_LH       = (0x21 << 26),
+    OPC_LWL      = (0x22 << 26),
+    OPC_LW       = (0x23 << 26),
+    OPC_LBU      = (0x24 << 26),
+    OPC_LHU      = (0x25 << 26),
+    OPC_LWR      = (0x26 << 26),
+    OPC_LWU      = (0x27 << 26),
+    OPC_SB       = (0x28 << 26),
+    OPC_SH       = (0x29 << 26),
+    OPC_SWL      = (0x2A << 26),
+    OPC_SW       = (0x2B << 26),
+    OPC_SDL      = (0x2C << 26),
+    OPC_SDR      = (0x2D << 26),
+    OPC_SWR      = (0x2E << 26),
+    OPC_LL       = (0x30 << 26),
+    OPC_LLD      = (0x34 << 26),
+    OPC_LD       = (0x37 << 26),
+    OPC_SC       = (0x38 << 26),
+    OPC_SCD      = (0x3C << 26),
+    OPC_SD       = (0x3F << 26),
     /* Floating point load/store */
-    OPC_LWC1     = 0x31,
-    OPC_LWC2     = 0x32,
-    OPC_LDC1     = 0x35,
-    OPC_LDC2     = 0x36,
-    OPC_SWC1     = 0x39,
-    OPC_SWC2     = 0x3A,
-    OPC_SDC1     = 0x3D,
-    OPC_SDC2     = 0x3E,
+    OPC_LWC1     = (0x31 << 26),
+    OPC_LWC2     = (0x32 << 26),
+    OPC_LDC1     = (0x35 << 26),
+    OPC_LDC2     = (0x36 << 26),
+    OPC_SWC1     = (0x39 << 26),
+    OPC_SWC2     = (0x3A << 26),
+    OPC_SDC1     = (0x3D << 26),
+    OPC_SDC2     = (0x3E << 26),
+    /* MDMX ASE specific */
+    OPC_MDMX     = (0x1E << 26),
     /* Cache and prefetch */
-    OPC_CACHE    = 0x2F,
-    OPC_PREF     = 0x33,
+    OPC_CACHE    = (0x2F << 26),
+    OPC_PREF     = (0x33 << 26),
+    /* Reserved major opcode */
+    OPC_MAJOR3B_RESERVED = (0x3B << 26),
 };
 
 /* MIPS special opcodes */
+#define MASK_SPECIAL(op)   MASK_OP_MAJOR(op) | (op & 0x3F)
+
 enum {
     /* Shifts */
-    OPC_SLL      = 0x00 | EXT_SPECIAL,
+    OPC_SLL      = 0x00 | OPC_SPECIAL,
     /* NOP is SLL r0, r0, 0   */
     /* SSNOP is SLL r0, r0, 1 */
-    OPC_SRL      = 0x02 | EXT_SPECIAL,
-    OPC_SRA      = 0x03 | EXT_SPECIAL,
-    OPC_SLLV     = 0x04 | EXT_SPECIAL,
-    OPC_SRLV     = 0x06 | EXT_SPECIAL,
-    OPC_SRAV     = 0x07 | EXT_SPECIAL,
+    /* EHB is SLL r0, r0, 3 */
+    OPC_SRL      = 0x02 | OPC_SPECIAL, /* also ROTR */
+    OPC_SRA      = 0x03 | OPC_SPECIAL,
+    OPC_SLLV     = 0x04 | OPC_SPECIAL,
+    OPC_SRLV     = 0x06 | OPC_SPECIAL,
+    OPC_SRAV     = 0x07 | OPC_SPECIAL,
+    OPC_DSLLV    = 0x14 | OPC_SPECIAL,
+    OPC_DSRLV    = 0x16 | OPC_SPECIAL, /* also DROTRV */
+    OPC_DSRAV    = 0x17 | OPC_SPECIAL,
+    OPC_DSLL     = 0x38 | OPC_SPECIAL,
+    OPC_DSRL     = 0x3A | OPC_SPECIAL, /* also DROTR */
+    OPC_DSRA     = 0x3B | OPC_SPECIAL,
+    OPC_DSLL32   = 0x3C | OPC_SPECIAL,
+    OPC_DSRL32   = 0x3E | OPC_SPECIAL, /* also DROTR32 */
+    OPC_DSRA32   = 0x3F | OPC_SPECIAL,
     /* Multiplication / division */
-    OPC_MULT     = 0x18 | EXT_SPECIAL,
-    OPC_MULTU    = 0x19 | EXT_SPECIAL,
-    OPC_DIV      = 0x1A | EXT_SPECIAL,
-    OPC_DIVU     = 0x1B | EXT_SPECIAL,
+    OPC_MULT     = 0x18 | OPC_SPECIAL,
+    OPC_MULTU    = 0x19 | OPC_SPECIAL,
+    OPC_DIV      = 0x1A | OPC_SPECIAL,
+    OPC_DIVU     = 0x1B | OPC_SPECIAL,
+    OPC_DMULT    = 0x1C | OPC_SPECIAL,
+    OPC_DMULTU   = 0x1D | OPC_SPECIAL,
+    OPC_DDIV     = 0x1E | OPC_SPECIAL,
+    OPC_DDIVU    = 0x1F | OPC_SPECIAL,
     /* 2 registers arithmetic / logic */
-    OPC_ADD      = 0x20 | EXT_SPECIAL,
-    OPC_ADDU     = 0x21 | EXT_SPECIAL,
-    OPC_SUB      = 0x22 | EXT_SPECIAL,
-    OPC_SUBU     = 0x23 | EXT_SPECIAL,
-    OPC_AND      = 0x24 | EXT_SPECIAL,
-    OPC_OR       = 0x25 | EXT_SPECIAL,
-    OPC_XOR      = 0x26 | EXT_SPECIAL,
-    OPC_NOR      = 0x27 | EXT_SPECIAL,
-    OPC_SLT      = 0x2A | EXT_SPECIAL,
-    OPC_SLTU     = 0x2B | EXT_SPECIAL,
+    OPC_ADD      = 0x20 | OPC_SPECIAL,
+    OPC_ADDU     = 0x21 | OPC_SPECIAL,
+    OPC_SUB      = 0x22 | OPC_SPECIAL,
+    OPC_SUBU     = 0x23 | OPC_SPECIAL,
+    OPC_AND      = 0x24 | OPC_SPECIAL,
+    OPC_OR       = 0x25 | OPC_SPECIAL,
+    OPC_XOR      = 0x26 | OPC_SPECIAL,
+    OPC_NOR      = 0x27 | OPC_SPECIAL,
+    OPC_SLT      = 0x2A | OPC_SPECIAL,
+    OPC_SLTU     = 0x2B | OPC_SPECIAL,
+    OPC_DADD     = 0x2C | OPC_SPECIAL,
+    OPC_DADDU    = 0x2D | OPC_SPECIAL,
+    OPC_DSUB     = 0x2E | OPC_SPECIAL,
+    OPC_DSUBU    = 0x2F | OPC_SPECIAL,
     /* Jumps */
-    OPC_JR       = 0x08 | EXT_SPECIAL,
-    OPC_JALR     = 0x09 | EXT_SPECIAL,
+    OPC_JR       = 0x08 | OPC_SPECIAL, /* Also JR.HB */
+    OPC_JALR     = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
     /* Traps */
-    OPC_TGE      = 0x30 | EXT_SPECIAL,
-    OPC_TGEU     = 0x31 | EXT_SPECIAL,
-    OPC_TLT      = 0x32 | EXT_SPECIAL,
-    OPC_TLTU     = 0x33 | EXT_SPECIAL,
-    OPC_TEQ      = 0x34 | EXT_SPECIAL,
-    OPC_TNE      = 0x36 | EXT_SPECIAL,
+    OPC_TGE      = 0x30 | OPC_SPECIAL,
+    OPC_TGEU     = 0x31 | OPC_SPECIAL,
+    OPC_TLT      = 0x32 | OPC_SPECIAL,
+    OPC_TLTU     = 0x33 | OPC_SPECIAL,
+    OPC_TEQ      = 0x34 | OPC_SPECIAL,
+    OPC_TNE      = 0x36 | OPC_SPECIAL,
     /* HI / LO registers load & stores */
-    OPC_MFHI     = 0x10 | EXT_SPECIAL,
-    OPC_MTHI     = 0x11 | EXT_SPECIAL,
-    OPC_MFLO     = 0x12 | EXT_SPECIAL,
-    OPC_MTLO     = 0x13 | EXT_SPECIAL,
+    OPC_MFHI     = 0x10 | OPC_SPECIAL,
+    OPC_MTHI     = 0x11 | OPC_SPECIAL,
+    OPC_MFLO     = 0x12 | OPC_SPECIAL,
+    OPC_MTLO     = 0x13 | OPC_SPECIAL,
     /* Conditional moves */
-    OPC_MOVZ     = 0x0A | EXT_SPECIAL,
-    OPC_MOVN     = 0x0B | EXT_SPECIAL,
+    OPC_MOVZ     = 0x0A | OPC_SPECIAL,
+    OPC_MOVN     = 0x0B | OPC_SPECIAL,
 
-    OPC_MOVCI    = 0x01 | EXT_SPECIAL,
+    OPC_MOVCI    = 0x01 | OPC_SPECIAL,
 
     /* Special */
-    OPC_PMON     = 0x05 | EXT_SPECIAL,
-    OPC_SYSCALL  = 0x0C | EXT_SPECIAL,
-    OPC_BREAK    = 0x0D | EXT_SPECIAL,
-    OPC_SYNC     = 0x0F | EXT_SPECIAL,
+    OPC_PMON     = 0x05 | OPC_SPECIAL, /* inofficial */
+    OPC_SYSCALL  = 0x0C | OPC_SPECIAL,
+    OPC_BREAK    = 0x0D | OPC_SPECIAL,
+    OPC_SPIM     = 0x0E | OPC_SPECIAL, /* inofficial */
+    OPC_SYNC     = 0x0F | OPC_SPECIAL,
+
+    OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL,
+    OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL,
+    OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL,
+    OPC_SPECIAL35_RESERVED = 0x35 | OPC_SPECIAL,
+    OPC_SPECIAL37_RESERVED = 0x37 | OPC_SPECIAL,
+    OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL,
+    OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL,
+};
+
+/* REGIMM (rt field) opcodes */
+#define MASK_REGIMM(op)    MASK_OP_MAJOR(op) | (op & (0x1F << 16))
+
+enum {
+    OPC_BLTZ     = (0x00 << 16) | OPC_REGIMM,
+    OPC_BLTZL    = (0x02 << 16) | OPC_REGIMM,
+    OPC_BGEZ     = (0x01 << 16) | OPC_REGIMM,
+    OPC_BGEZL    = (0x03 << 16) | OPC_REGIMM,
+    OPC_BLTZAL   = (0x10 << 16) | OPC_REGIMM,
+    OPC_BLTZALL  = (0x12 << 16) | OPC_REGIMM,
+    OPC_BGEZAL   = (0x11 << 16) | OPC_REGIMM,
+    OPC_BGEZALL  = (0x13 << 16) | OPC_REGIMM,
+    OPC_TGEI     = (0x08 << 16) | OPC_REGIMM,
+    OPC_TGEIU    = (0x09 << 16) | OPC_REGIMM,
+    OPC_TLTI     = (0x0A << 16) | OPC_REGIMM,
+    OPC_TLTIU    = (0x0B << 16) | OPC_REGIMM,
+    OPC_TEQI     = (0x0C << 16) | OPC_REGIMM,
+    OPC_TNEI     = (0x0E << 16) | OPC_REGIMM,
+    OPC_SYNCI    = (0x1F << 16) | OPC_REGIMM,
 };
 
+/* Special2 opcodes */
+#define MASK_SPECIAL2(op)  MASK_OP_MAJOR(op) | (op & 0x3F)
+
 enum {
-    /* Mutiply & xxx operations */
-    OPC_MADD     = 0x00 | EXT_SPECIAL2,
-    OPC_MADDU    = 0x01 | EXT_SPECIAL2,
-    OPC_MUL      = 0x02 | EXT_SPECIAL2,
-    OPC_MSUB     = 0x04 | EXT_SPECIAL2,
-    OPC_MSUBU    = 0x05 | EXT_SPECIAL2,
+    /* Multiply & xxx operations */
+    OPC_MADD     = 0x00 | OPC_SPECIAL2,
+    OPC_MADDU    = 0x01 | OPC_SPECIAL2,
+    OPC_MUL      = 0x02 | OPC_SPECIAL2,
+    OPC_MSUB     = 0x04 | OPC_SPECIAL2,
+    OPC_MSUBU    = 0x05 | OPC_SPECIAL2,
     /* Misc */
-    OPC_CLZ      = 0x20 | EXT_SPECIAL2,
-    OPC_CLO      = 0x21 | EXT_SPECIAL2,
+    OPC_CLZ      = 0x20 | OPC_SPECIAL2,
+    OPC_CLO      = 0x21 | OPC_SPECIAL2,
+    OPC_DCLZ     = 0x24 | OPC_SPECIAL2,
+    OPC_DCLO     = 0x25 | OPC_SPECIAL2,
     /* Special */
-    OPC_SDBBP    = 0x3F | EXT_SPECIAL2,
+    OPC_SDBBP    = 0x3F | OPC_SPECIAL2,
 };
 
-/* Branch REGIMM */
+/* Special3 opcodes */
+#define MASK_SPECIAL3(op)  MASK_OP_MAJOR(op) | (op & 0x3F)
+
 enum {
-    OPC_BLTZ     = 0x00 | EXT_REGIMM,
-    OPC_BLTZL    = 0x02 | EXT_REGIMM,
-    OPC_BGEZ     = 0x01 | EXT_REGIMM,
-    OPC_BGEZL    = 0x03 | EXT_REGIMM,
-    OPC_BLTZAL   = 0x10 | EXT_REGIMM,
-    OPC_BLTZALL  = 0x12 | EXT_REGIMM,
-    OPC_BGEZAL   = 0x11 | EXT_REGIMM,
-    OPC_BGEZALL  = 0x13 | EXT_REGIMM,
-    OPC_TGEI     = 0x08 | EXT_REGIMM,
-    OPC_TGEIU    = 0x09 | EXT_REGIMM,
-    OPC_TLTI     = 0x0A | EXT_REGIMM,
-    OPC_TLTIU    = 0x0B | EXT_REGIMM,
-    OPC_TEQI     = 0x0C | EXT_REGIMM,
-    OPC_TNEI     = 0x0E | EXT_REGIMM,
+    OPC_EXT      = 0x00 | OPC_SPECIAL3,
+    OPC_DEXTM    = 0x01 | OPC_SPECIAL3,
+    OPC_DEXTU    = 0x02 | OPC_SPECIAL3,
+    OPC_DEXT     = 0x03 | OPC_SPECIAL3,
+    OPC_INS      = 0x04 | OPC_SPECIAL3,
+    OPC_DINSM    = 0x05 | OPC_SPECIAL3,
+    OPC_DINSU    = 0x06 | OPC_SPECIAL3,
+    OPC_DINS     = 0x07 | OPC_SPECIAL3,
+    OPC_BSHFL    = 0x20 | OPC_SPECIAL3,
+    OPC_DBSHFL   = 0x24 | OPC_SPECIAL3,
+    OPC_RDHWR    = 0x3B | OPC_SPECIAL3,
 };
 
+/* BSHFL opcodes */
+#define MASK_BSHFL(op)     MASK_SPECIAL3(op) | (op & (0x1F << 6))
+
 enum {
-    /* Coprocessor 0 (MMU) */
-    OPC_MFC0     = 0x00 | EXT_CP0,
-    OPC_MTC0     = 0x04 | EXT_CP0,
-    OPC_TLBR     = 0x01 | EXT_CP0,
-    OPC_TLBWI    = 0x02 | EXT_CP0,
-    OPC_TLBWR    = 0x06 | EXT_CP0,
-    OPC_TLBP     = 0x08 | EXT_CP0,
-    OPC_ERET     = 0x18 | EXT_CP0,
-    OPC_DERET    = 0x1F | EXT_CP0,
-    OPC_WAIT     = 0x20 | EXT_CP0,
+    OPC_WSBH     = (0x02 << 6) | OPC_BSHFL,
+    OPC_SEB      = (0x10 << 6) | OPC_BSHFL,
+    OPC_SEH      = (0x18 << 6) | OPC_BSHFL,
 };
 
-#ifdef MIPS_USES_FPU
+/* DBSHFL opcodes */
+#define MASK_DBSHFL(op)    MASK_SPECIAL3(op) | (op & (0x1F << 6))
+
 enum {
-    /* Coprocessor 1 (FPU) */
-    OPC_MFC1     = 0x00 | EXT_CP1,
-    OPC_MTC1     = 0x04 | EXT_CP1,
-    OPC_CFC1     = 0x02 | EXT_CP1,
-    OPC_CTC1     = 0x06 | EXT_CP1,
+    OPC_DSBH     = (0x02 << 6) | OPC_DBSHFL,
+    OPC_DSHD     = (0x05 << 6) | OPC_DBSHFL,
+};
+
+/* Coprocessor 0 (rs field) */
+#define MASK_CP0(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+
+enum {
+    OPC_MFC0     = (0x00 << 21) | OPC_CP0,
+    OPC_DMFC0    = (0x01 << 21) | OPC_CP0,
+    OPC_MTC0     = (0x04 << 21) | OPC_CP0,
+    OPC_DMTC0    = (0x05 << 21) | OPC_CP0,
+    OPC_RDPGPR   = (0x0A << 21) | OPC_CP0,
+    OPC_MFMC0    = (0x0B << 21) | OPC_CP0,
+    OPC_WRPGPR   = (0x0E << 21) | OPC_CP0,
+    OPC_C0       = (0x10 << 21) | OPC_CP0,
+    OPC_C0_FIRST = (0x10 << 21) | OPC_CP0,
+    OPC_C0_LAST  = (0x1F << 21) | OPC_CP0,
+};
+
+/* MFMC0 opcodes */
+#define MASK_MFMC0(op)     MASK_CP0(op) | (op & ((0x0C << 11) | (1 << 5)))
+
+enum {
+    OPC_DI       = (0 << 5) | (0x0C << 11) | OPC_MFMC0,
+    OPC_EI       = (1 << 5) | (0x0C << 11) | OPC_MFMC0,
+};
+
+/* Coprocessor 0 (with rs == C0) */
+#define MASK_C0(op)        MASK_CP0(op) | (op & 0x3F)
+
+enum {
+    OPC_TLBR     = 0x01 | OPC_C0,
+    OPC_TLBWI    = 0x02 | OPC_C0,
+    OPC_TLBWR    = 0x06 | OPC_C0,
+    OPC_TLBP     = 0x08 | OPC_C0,
+    OPC_RFE      = 0x10 | OPC_C0,
+    OPC_ERET     = 0x18 | OPC_C0,
+    OPC_DERET    = 0x1F | OPC_C0,
+    OPC_WAIT     = 0x20 | OPC_C0,
+};
+
+/* Coprocessor 1 (rs field) */
+#define MASK_CP1(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+
+enum {
+    OPC_MFC1     = (0x00 << 21) | OPC_CP1,
+    OPC_DMFC1    = (0x01 << 21) | OPC_CP1,
+    OPC_CFC1     = (0x02 << 21) | OPC_CP1,
+    OPC_MFHCI    = (0x03 << 21) | OPC_CP1,
+    OPC_MTC1     = (0x04 << 21) | OPC_CP1,
+    OPC_DMTC1    = (0x05 << 21) | OPC_CP1,
+    OPC_CTC1     = (0x06 << 21) | OPC_CP1,
+    OPC_MTHCI    = (0x07 << 21) | OPC_CP1,
+    OPC_BC1      = (0x08 << 21) | OPC_CP1, /* bc */
+    OPC_S_FMT    = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */
+    OPC_D_FMT    = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */
+    OPC_E_FMT    = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */
+    OPC_Q_FMT    = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */
+    OPC_W_FMT    = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */
+    OPC_L_FMT    = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */
+};
+
+enum {
+    OPC_BC1F     = (0x00 << 16) | OPC_BC1,
+    OPC_BC1T     = (0x01 << 16) | OPC_BC1,
+    OPC_BC1FL    = (0x02 << 16) | OPC_BC1,
+    OPC_BC1TL    = (0x03 << 16) | OPC_BC1,
 };
-#endif
+
+#define MASK_CP1_BCOND(op)      MASK_CP1(op) | (op & ((0x1F << 21) | (0x3 << 
16)))
+#define MASK_CP1_FUNC(op)       MASK_CP1(op) | (op & ((0x1F << 21) | 0x3F))
+
+#define MASK_CP2(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+#define MASK_CP3(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
 
 const unsigned char *regnames[] =
     { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
@@ -260,8 +389,7 @@
 GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
 GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
 
-#ifdef MIPS_USES_FPU
-const unsigned char *fregnames[] =
+static const char *fregnames[] =
     { "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
       "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
       "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
@@ -344,8 +472,6 @@
 FOP_CONDS(d)
 FOP_CONDS(s)
 
-#endif
-
 typedef struct DisasContext {
     struct TranslationBlock *tb;
     target_ulong pc, saved_pc;
@@ -410,9 +536,7 @@
     }                                                                         \
 } while (0)
 
-#ifdef MIPS_USES_FPU
-
-# define GEN_LOAD_FREG_FTN(FTn, Fn)                                           \
+#define GEN_LOAD_FREG_FTN(FTn, Fn)                                            \
 do {                                                                          \
     glue(gen_op_load_fpr_, FTn)(Fn);                                          \
 } while (0)
@@ -422,8 +546,6 @@
     glue(gen_op_store_fpr_, FTn)(Fn);                                         \
 } while (0)
 
-#endif
-
 static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
 {
 #if defined MIPS_DEBUG_DISAS
@@ -487,7 +609,7 @@
 }
 #endif
 
-#ifdef TARGET_MIPS64
+#ifdef MIPS_HAS_MIPS64
 OP_LD_TABLE(d);
 OP_LD_TABLE(dl);
 OP_LD_TABLE(dr);
@@ -510,18 +632,16 @@
 OP_ST_TABLE(b);
 OP_LD_TABLE(l);
 OP_ST_TABLE(c);
-#ifdef MIPS_USES_FPU
 OP_LD_TABLE(wc1);
 OP_ST_TABLE(wc1);
 OP_LD_TABLE(dc1);
 OP_ST_TABLE(dc1);
-#endif
 
 /* Load and store */
-static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
+static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
                       int base, int16_t offset)
 {
-    const unsigned char *opn = "unk";
+    const char *opn = "unk";
 
     if (base == 0) {
         GEN_LOAD_IMM_TN(T0, offset);
@@ -536,23 +656,27 @@
      * memory access
      */
     switch (opc) {
-#if defined(TARGET_MIPS64)
+#ifdef MIPS_HAS_MIPS64
     case OPC_LD:
-#if defined (MIPS_HAS_UNALIGNED_LS)
-    case OPC_ULD:
-#endif
         op_ldst(ld);
         GEN_STORE_TN_REG(rt, T0);
         opn = "ld";
         break;
+    case OPC_LLD:
+        op_ldst(lld);
+        GEN_STORE_TN_REG(rt, T0);
+        opn = "lld";
+        break;
     case OPC_SD:
-#if defined (MIPS_HAS_UNALIGNED_LS)
-    case OPC_USD:
-#endif
         GEN_LOAD_REG_TN(T1, rt);
         op_ldst(sd);
         opn = "sd";
         break;
+    case OPC_SCD:
+        GEN_LOAD_REG_TN(T1, rt);
+        op_ldst(scd);
+        opn = "scd";
+        break;
     case OPC_LDL:
         op_ldst(ldl);
         GEN_STORE_TN_REG(rt, T0);
@@ -575,9 +699,6 @@
         break;
 #endif
     case OPC_LW:
-#if defined (MIPS_HAS_UNALIGNED_LS)
-    case OPC_ULW:
-#endif
         op_ldst(lw);
         GEN_STORE_TN_REG(rt, T0);
         opn = "lw";
@@ -588,33 +709,21 @@
         opn = "lwu";
         break;
     case OPC_SW:
-#if defined (MIPS_HAS_UNALIGNED_LS)
-    case OPC_USW:
-#endif
         GEN_LOAD_REG_TN(T1, rt);
         op_ldst(sw);
         opn = "sw";
         break;
     case OPC_LH:
-#if defined (MIPS_HAS_UNALIGNED_LS)
-    case OPC_ULH:
-#endif
         op_ldst(lh);
         GEN_STORE_TN_REG(rt, T0);
         opn = "lh";
         break;
     case OPC_SH:
-#if defined (MIPS_HAS_UNALIGNED_LS)
-    case OPC_USH:
-#endif
         GEN_LOAD_REG_TN(T1, rt);
         op_ldst(sh);
         opn = "sh";
         break;
     case OPC_LHU:
-#if defined (MIPS_HAS_UNALIGNED_LS)
-    case OPC_ULHU:
-#endif
         op_ldst(lhu);
         GEN_STORE_TN_REG(rt, T0);
         opn = "lhu";
@@ -675,13 +784,11 @@
     MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
 }
 
-#ifdef MIPS_USES_FPU
-
 /* Load and store */
-static void gen_flt_ldst (DisasContext *ctx, uint16_t opc, int ft,
+static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
                       int base, int16_t offset)
 {
-    const unsigned char *opn = "unk";
+    const char *opn = "unk";
 
     if (base == 0) {
         GEN_LOAD_IMM_TN(T0, offset);
@@ -718,21 +825,20 @@
         break;
     default:
         MIPS_INVAL("float load/store");
-        generate_exception(ctx, EXCP_CpU);
+        generate_exception_err(ctx, EXCP_CpU, 1);
         return;
     }
     MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
 }
-#endif
 
 /* Arithmetic with immediate operand */
-static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
+static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
                            int rs, int16_t imm)
 {
     uint32_t uimm;
-    const unsigned char *opn = "unk";
+    const char *opn = "unk";
 
-    if (rt == 0 && opc != OPC_ADDI) {
+    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.
          */
@@ -740,8 +846,9 @@
         return;
     }
     if (opc == OPC_ADDI || opc == OPC_ADDIU ||
+        opc == OPC_DADDI || opc == OPC_DADDIU ||
         opc == OPC_SLTI || opc == OPC_SLTIU)
-        uimm = (int32_t)imm; /* Sign extent to 32 bits */
+        uimm = (int32_t)imm; /* Sign extend to 32 bits */
     else
         uimm = (uint16_t)imm;
     if (opc != OPC_LUI) {
@@ -761,6 +868,17 @@
         gen_op_add();
         opn = "addiu";
         break;
+#ifdef MIPS_HAS_MIPS64
+    case OPC_DADDI:
+        save_cpu_state(ctx, 1);
+        gen_op_daddo();
+        opn = "daddi";
+        break;
+    case OPC_DADDIU:
+        gen_op_dadd();
+        opn = "daddiu";
+        break;
+#endif
     case OPC_SLTI:
         gen_op_lt();
         opn = "slti";
@@ -793,9 +911,50 @@
         opn = "sra";
         break;
     case OPC_SRL:
-        gen_op_srl();
-        opn = "srl";
+       if ((ctx->opcode >> 21) & 1) {
+            gen_op_rotr();
+            opn = "rotr";
+       } else {
+            gen_op_srl();
+            opn = "srl";
+       }
+        break;
+#ifdef MIPS_HAS_MIPS64
+    case OPC_DSLL:
+        gen_op_dsll();
+        opn = "dsll";
+        break;
+    case OPC_DSRA:
+        gen_op_dsra();
+        opn = "dsra";
+        break;
+    case OPC_DSRL:
+       if ((ctx->opcode >> 21) & 1) {
+            gen_op_drotr();
+            opn = "drotr";
+       } else {
+            gen_op_dsrl();
+            opn = "dsrl";
+       }
+        break;
+    case OPC_DSLL32:
+        gen_op_dsll32();
+        opn = "dsll32";
+        break;
+    case OPC_DSRA32:
+        gen_op_dsra32();
+        opn = "dsra32";
+        break;
+    case OPC_DSRL32:
+       if ((ctx->opcode >> 21) & 1) {
+            gen_op_drotr32();
+            opn = "drotr32";
+       } else {
+            gen_op_dsrl32();
+            opn = "dsrl32";
+       }
         break;
+#endif
     default:
         MIPS_INVAL("imm arith");
         generate_exception(ctx, EXCP_RI);
@@ -806,12 +965,13 @@
 }
 
 /* Arithmetic */
-static void gen_arith (DisasContext *ctx, uint16_t opc,
+static void gen_arith (DisasContext *ctx, uint32_t opc,
                        int rd, int rs, int rt)
 {
-    const unsigned char *opn = "unk";
+    const char *opn = "unk";
 
-    if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) {
+    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.
          */
@@ -839,6 +999,26 @@
         gen_op_sub();
         opn = "subu";
         break;
+#ifdef MIPS_HAS_MIPS64
+    case OPC_DADD:
+        save_cpu_state(ctx, 1);
+        gen_op_daddo();
+        opn = "dadd";
+        break;
+    case OPC_DADDU:
+        gen_op_dadd();
+        opn = "daddu";
+        break;
+    case OPC_DSUB:
+        save_cpu_state(ctx, 1);
+        gen_op_dsubo();
+        opn = "dsub";
+        break;
+    case OPC_DSUBU:
+        gen_op_dsub();
+        opn = "dsubu";
+        break;
+#endif
     case OPC_SLT:
         gen_op_lt();
         opn = "slt";
@@ -884,9 +1064,33 @@
         opn = "srav";
         break;
     case OPC_SRLV:
-        gen_op_srlv();
-        opn = "srlv";
+       if ((ctx->opcode >> 6) & 1) {
+            gen_op_rotrv();
+            opn = "rotrv";
+       } else {
+            gen_op_srlv();
+            opn = "srlv";
+       }
+        break;
+#ifdef MIPS_HAS_MIPS64
+    case OPC_DSLLV:
+        gen_op_dsllv();
+        opn = "dsllv";
+        break;
+    case OPC_DSRAV:
+        gen_op_dsrav();
+        opn = "dsrav";
+        break;
+    case OPC_DSRLV:
+       if ((ctx->opcode >> 6) & 1) {
+            gen_op_drotrv();
+            opn = "drotrv";
+       } else {
+            gen_op_dsrlv();
+            opn = "dsrlv";
+       }
         break;
+#endif
     default:
         MIPS_INVAL("arith");
         generate_exception(ctx, EXCP_RI);
@@ -898,9 +1102,9 @@
 }
 
 /* Arithmetic on HI/LO registers */
-static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg)
+static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
 {
-    const unsigned char *opn = "unk";
+    const char *opn = "unk";
 
     if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
         /* Treat as a NOP */
@@ -936,10 +1140,10 @@
     MIPS_DEBUG("%s %s", opn, regnames[reg]);
 }
 
-static void gen_muldiv (DisasContext *ctx, uint16_t opc,
+static void gen_muldiv (DisasContext *ctx, uint32_t opc,
                         int rs, int rt)
 {
-    const unsigned char *opn = "unk";
+    const char *opn = "unk";
 
     GEN_LOAD_REG_TN(T0, rs);
     GEN_LOAD_REG_TN(T1, rt);
@@ -960,6 +1164,24 @@
         gen_op_multu();
         opn = "multu";
         break;
+#ifdef MIPS_HAS_MIPS64
+    case OPC_DDIV:
+        gen_op_ddiv();
+        opn = "ddiv";
+        break;
+    case OPC_DDIVU:
+        gen_op_ddivu();
+        opn = "ddivu";
+        break;
+    case OPC_DMULT:
+        gen_op_dmult();
+        opn = "dmult";
+        break;
+    case OPC_DMULTU:
+        gen_op_dmultu();
+        opn = "dmultu";
+        break;
+#endif
     case OPC_MADD:
         gen_op_madd();
         opn = "madd";
@@ -984,10 +1206,10 @@
     MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
 }
 
-static void gen_cl (DisasContext *ctx, uint16_t opc,
+static void gen_cl (DisasContext *ctx, uint32_t opc,
                     int rd, int rs)
 {
-    const unsigned char *opn = "unk";
+    const char *opn = "unk";
     if (rd == 0) {
         /* Treat as a NOP */
         MIPS_DEBUG("NOP");
@@ -996,15 +1218,23 @@
     GEN_LOAD_REG_TN(T0, rs);
     switch (opc) {
     case OPC_CLO:
-        /* CLO */
         gen_op_clo();
         opn = "clo";
         break;
     case OPC_CLZ:
-        /* CLZ */
         gen_op_clz();
         opn = "clz";
         break;
+#ifdef MIPS_HAS_MIPS64
+    case OPC_DCLO:
+        gen_op_dclo();
+        opn = "dclo";
+        break;
+    case OPC_DCLZ:
+        gen_op_dclz();
+        opn = "dclz";
+        break;
+#endif
     default:
         MIPS_INVAL("CLx");
         generate_exception(ctx, EXCP_RI);
@@ -1015,7 +1245,7 @@
 }
 
 /* Traps */
-static void gen_trap (DisasContext *ctx, uint16_t opc,
+static void gen_trap (DisasContext *ctx, uint32_t opc,
                       int rs, int rt, int16_t imm)
 {
     int cond;
@@ -1130,7 +1360,7 @@
 }
 
 /* Branches (before delay slot) */
-static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
+static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
                                 int rs, int rt, int32_t offset)
 {
     target_ulong btarget;
@@ -1180,8 +1410,9 @@
     case OPC_JR:
     case OPC_JALR:
         /* Jump to register */
-        if (offset != 0) {
-            /* Only hint = 0 is valid */
+        if (offset != 0 && offset != 16) {
+            /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
+              others are reserved. */
             generate_exception(ctx, EXCP_RI);
             return;
         }
@@ -1348,81 +1579,330 @@
     return;
 }
 
+/* special3 bitfield operations */
+static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
+                       int rs, int pos, int size)
+{
+    int p = pos & 0x1F;
+    int sz = (size & 0x1F) + 1;
+
+    GEN_LOAD_REG_TN(T1, rs);
+    switch (opc) {
+    case OPC_EXT:
+       gen_op_ext(p, sz);
+        break;
+    case OPC_DEXTM:
+       gen_op_dextm(p, sz);
+        break;
+    case OPC_DEXTU:
+       gen_op_dextu(p, sz);
+        break;
+    case OPC_DEXT:
+       gen_op_dext(p, sz);
+        break;
+    case OPC_INS:
+       GEN_LOAD_REG_TN(T2, rt);
+       gen_op_ins(p, sz);
+        break;
+    case OPC_DINSM:
+       GEN_LOAD_REG_TN(T2, rt);
+       gen_op_dinsm(p, sz);
+        break;
+    case OPC_DINSU:
+       GEN_LOAD_REG_TN(T2, rt);
+       gen_op_dinsu(p, sz);
+        break;
+    case OPC_DINS:
+       GEN_LOAD_REG_TN(T2, rt);
+       gen_op_dins(p, sz);
+        break;
+    default:
+        MIPS_INVAL("bitops");
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+    GEN_STORE_TN_REG(rt, T0);
+}
+
 /* CP0 (MMU and control) */
 static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
 {
-    const unsigned char *rn;
+    const char *rn = "invalid";
 
-    if (sel != 0 && reg != 16 && reg != 28) {
-        rn = "invalid";
-        goto die;
-    }
     switch (reg) {
     case 0:
-        gen_op_mfc0_index();
-        rn = "Index";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_index();
+            rn = "Index";
+            break;
+        case 1:
+//         gen_op_mfc0_mvpcontrol(); /* MT ASE */
+            rn = "MVPControl";
+//         break;
+        case 2:
+//         gen_op_mfc0_mvpconf0(); /* MT ASE */
+            rn = "MVPConf0";
+//         break;
+        case 3:
+//         gen_op_mfc0_mvpconf1(); /* MT ASE */
+            rn = "MVPConf1";
+//         break;
+        default:
+            goto die;
+        }
         break;
     case 1:
-        gen_op_mfc0_random();
-        rn = "Random";
+        switch (sel) {
+        case 0:
+            gen_op_mfc0_random();
+            rn = "Random";
+           break;
+        case 1:
+//         gen_op_mfc0_vpecontrol(); /* MT ASE */
+            rn = "VPEControl";
+//         break;
+        case 2:
+//         gen_op_mfc0_vpeconf0(); /* MT ASE */
+            rn = "VPEConf0";
+//         break;
+        case 3:
+//         gen_op_mfc0_vpeconf1(); /* MT ASE */
+            rn = "VPEConf1";
+//         break;
+        case 4:
+//         gen_op_mfc0_YQMask(); /* MT ASE */
+            rn = "YQMask";
+//         break;
+        case 5:
+//         gen_op_mfc0_vpeschedule(); /* MT ASE */
+            rn = "VPESchedule";
+//         break;
+        case 6:
+//         gen_op_mfc0_vpeschefback(); /* MT ASE */
+            rn = "VPEScheFBack";
+//         break;
+        case 7:
+//         gen_op_mfc0_vpeopt(); /* MT ASE */
+            rn = "VPEOpt";
+//         break;
+        default:
+            goto die;
+        }
         break;
     case 2:
-        gen_op_mfc0_entrylo0();
-        rn = "EntryLo0";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_entrylo0();
+           rn = "EntryLo0";
+           break;
+        case 1:
+//         gen_op_mfc0_tcstatus(); /* MT ASE */
+           rn = "TCStatus";
+//         break;
+        case 2:
+//         gen_op_mfc0_tcbind(); /* MT ASE */
+           rn = "TCBind";
+//         break;
+        case 3:
+//         gen_op_mfc0_tcrestart(); /* MT ASE */
+           rn = "TCRestart";
+//         break;
+        case 4:
+//         gen_op_mfc0_tchalt(); /* MT ASE */
+           rn = "TCHalt";
+//         break;
+        case 5:
+//         gen_op_mfc0_tccontext(); /* MT ASE */
+           rn = "TCContext";
+//         break;
+        case 6:
+//         gen_op_mfc0_tcschedule(); /* MT ASE */
+           rn = "TCSchedule";
+//         break;
+        case 7:
+//         gen_op_mfc0_tcschefback(); /* MT ASE */
+           rn = "TCScheFBack";
+//         break;
+        default:
+            goto die;
+        }
         break;
     case 3:
-//
-       /* also CONF */
-        gen_op_mfc0_entrylo1();
-        rn = "EntryLo1";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_entrylo1();
+           rn = "EntryLo1";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 4:
-        gen_op_mfc0_context();
-        rn = "Context";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_context();
+           rn = "Context";
+           break;
+        case 1:
+//         gen_op_mfc0_contextconfig(); /* SmartMIPS ASE */
+           rn = "ContextConfig";
+//         break;
+        default:
+            goto die;
+       }
         break;
     case 5:
-        gen_op_mfc0_pagemask();
-        rn = "PageMask";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_pagemask();
+           rn = "PageMask";
+           break;
+        case 1:
+           gen_op_mfc0_pagegrain();
+           rn = "PageGrain";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 6:
-        gen_op_mfc0_wired();
-        rn = "Wired";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_wired();
+           rn = "Wired";
+           break;
+        case 1:
+//         gen_op_mfc0_srsconf0(); /* shadow registers */
+           rn = "SRSConf0";
+//         break;
+        case 2:
+//         gen_op_mfc0_srsconf1(); /* shadow registers */
+           rn = "SRSConf1";
+//         break;
+        case 3:
+//         gen_op_mfc0_srsconf2(); /* shadow registers */
+           rn = "SRSConf2";
+//         break;
+        case 4:
+//         gen_op_mfc0_srsconf3(); /* shadow registers */
+           rn = "SRSConf3";
+//         break;
+        case 5:
+//         gen_op_mfc0_srsconf4(); /* shadow registers */
+           rn = "SRSConf4";
+//         break;
+        default:
+            goto die;
+       }
         break;
     case 7:
-//        gen_op_mfc0_info();
-        rn = "Info";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_hwrena();
+           rn = "HWREna";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 8:
-        gen_op_mfc0_badvaddr();
-        rn = "BadVaddr";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_badvaddr();
+           rn = "BadVaddr";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 9:
-        gen_op_mfc0_count();
-        rn = "Count";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_count();
+           rn = "Count";
+           break;
+       /* 6,7 are implementation dependent */
+        default:
+            goto die;
+       }
         break;
     case 10:
-        gen_op_mfc0_entryhi();
-        rn = "EntryHi";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_entryhi();
+           rn = "EntryHi";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 11:
-        gen_op_mfc0_compare();
-        rn = "Compare";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_compare();
+           rn = "Compare";
+           break;
+       /* 6,7 are implementation dependent */
+        default:
+            goto die;
+       }
         break;
     case 12:
-        gen_op_mfc0_status();
-        rn = "Status";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_status();
+           rn = "Status";
+           break;
+        case 1:
+           gen_op_mfc0_intctl();
+           rn = "IntCtl";
+           break;
+        case 2:
+           gen_op_mfc0_srsctl();
+           rn = "SRSCtl";
+           break;
+        case 3:
+//         gen_op_mfc0_srsmap(); /* shadow registers */
+           rn = "SRSMap";
+//         break;
+        default:
+            goto die;
+       }
         break;
     case 13:
-        gen_op_mfc0_cause();
-        rn = "Cause";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_cause();
+           rn = "Cause";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 14:
-        gen_op_mfc0_epc();
-        rn = "EPC";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_epc();
+           rn = "EPC";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 15:
-        gen_op_mfc0_prid();
-        rn = "PRid";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_prid();
+           rn = "PRid";
+           break;
+        case 1:
+           gen_op_mfc0_ebase();
+           rn = "EBase";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 16:
         switch (sel) {
@@ -1434,91 +1914,285 @@
            gen_op_mfc0_config1();
             rn = "Config1";
             break;
+        case 2:
+           gen_op_mfc0_config2();
+            rn = "Config2";
+            break;
+        case 3:
+           gen_op_mfc0_config3();
+            rn = "Config3";
+            break;
+       /* 6,7 are implementation dependent */
         default:
-            rn = "Unknown config register";
             goto die;
         }
         break;
     case 17:
-        gen_op_mfc0_lladdr();
-        rn = "LLAddr";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_lladdr();
+           rn = "LLAddr";
+           break;
+        default:
+            goto die;
+        }
         break;
     case 18:
-        gen_op_mfc0_watchlo();
-        rn = "WatchLo";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_watchlo0();
+           rn = "WatchLo";
+           break;
+        case 1:
+//         gen_op_mfc0_watchlo1();
+           rn = "WatchLo1";
+//         break;
+        case 2:
+//         gen_op_mfc0_watchlo2();
+           rn = "WatchLo2";
+//         break;
+        case 3:
+//         gen_op_mfc0_watchlo3();
+           rn = "WatchLo3";
+//         break;
+        case 4:
+//         gen_op_mfc0_watchlo4();
+           rn = "WatchLo4";
+//         break;
+        case 5:
+//         gen_op_mfc0_watchlo5();
+           rn = "WatchLo5";
+//         break;
+        case 6:
+//         gen_op_mfc0_watchlo6();
+           rn = "WatchLo6";
+//         break;
+        case 7:
+//         gen_op_mfc0_watchlo7();
+           rn = "WatchLo7";
+//         break;
+        default:
+            goto die;
+        }
         break;
     case 19:
-        gen_op_mfc0_watchhi();
-        rn = "WatchHi";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_watchhi0();
+           rn = "WatchHi";
+           break;
+        case 1:
+//         gen_op_mfc0_watchhi1();
+           rn = "WatchHi1";
+//         break;
+        case 2:
+//         gen_op_mfc0_watchhi2();
+           rn = "WatchHi2";
+//         break;
+        case 3:
+//         gen_op_mfc0_watchhi3();
+           rn = "WatchHi3";
+//         break;
+        case 4:
+//         gen_op_mfc0_watchhi4();
+           rn = "WatchHi4";
+//         break;
+        case 5:
+//         gen_op_mfc0_watchhi5();
+           rn = "WatchHi5";
+//         break;
+        case 6:
+//         gen_op_mfc0_watchhi6();
+           rn = "WatchHi6";
+//         break;
+        case 7:
+//         gen_op_mfc0_watchhi7();
+           rn = "WatchHi7";
+//         break;
+        default:
+            goto die;
+        }
         break;
     case 20:
-       /* 64 bit only */
-//        gen_op_mfc0_xcontext();
-        rn = "XContext";
+        switch (sel) {
+        case 0:
+           /* 64 bit MMU only */
+           gen_op_mfc0_xcontext();
+           rn = "XContext";
+           break;
+        default:
+            goto die;
+        }
         break;
     case 21:
-//        gen_op_mfc0_framemask();
-        rn = "Framemask";
+       /* Officially reserved, but sel 0 is used for R1x000 framemask */
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_framemask();
+           rn = "Framemask";
+           break;
+        default:
+            goto die;
+        }
         break;
     case 22:
-//        gen_op_mfc0_diagnostic();
-        rn = "'Diagnostic";
-        break;
+       /* ignored */
+       rn = "'Diagnostic"; /* implementation dependent */
+       break;
     case 23:
-        gen_op_mfc0_debug();
-        rn = "Debug";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_debug(); /* EJTAG support */
+           rn = "Debug";
+           break;
+        case 1:
+//         gen_op_mfc0_tracecontrol(); /* PDtrace support */
+           rn = "TraceControl";
+//         break;
+        case 2:
+//         gen_op_mfc0_tracecontrol2(); /* PDtrace support */
+           rn = "TraceControl2";
+//         break;
+        case 3:
+//         gen_op_mfc0_usertracedata(); /* PDtrace support */
+           rn = "UserTraceData";
+//         break;
+        case 4:
+//         gen_op_mfc0_debug(); /* PDtrace support */
+           rn = "TraceBPC";
+//         break;
+        default:
+            goto die;
+        }
         break;
     case 24:
-        gen_op_mfc0_depc();
-        rn = "DEPC";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_depc(); /* EJTAG support */
+           rn = "DEPC";
+           break;
+        default:
+            goto die;
+        }
         break;
     case 25:
-//        gen_op_mfc0_performance();
-        rn = "Performance";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_performance0();
+           rn = "Performance0";
+            break;
+        case 1:
+//         gen_op_mfc0_performance1();
+           rn = "Performance1";
+//         break;
+        case 2:
+//         gen_op_mfc0_performance2();
+           rn = "Performance2";
+//         break;
+        case 3:
+//         gen_op_mfc0_performance3();
+           rn = "Performance3";
+//         break;
+        case 4:
+//         gen_op_mfc0_performance4();
+           rn = "Performance4";
+//         break;
+        case 5:
+//         gen_op_mfc0_performance5();
+           rn = "Performance5";
+//         break;
+        case 6:
+//         gen_op_mfc0_performance6();
+           rn = "Performance6";
+//         break;
+        case 7:
+//         gen_op_mfc0_performance7();
+           rn = "Performance7";
+//         break;
+        default:
+            goto die;
+        }
         break;
     case 26:
-//        gen_op_mfc0_ecc();
-        rn = "ECC";
-        break;
+       rn = "ECC";
+       break;
     case 27:
-//        gen_op_mfc0_cacheerr();
-        rn = "CacheErr";
+        switch (sel) {
+        /* ignored */
+        case 0 ... 3:
+           rn = "CacheErr";
+           break;
+        default:
+            goto die;
+        }
         break;
     case 28:
         switch (sel) {
         case 0:
+        case 2:
+        case 4:
+        case 6:
             gen_op_mfc0_taglo();
             rn = "TagLo";
             break;
         case 1:
+        case 3:
+        case 5:
+        case 7:
             gen_op_mfc0_datalo();
             rn = "DataLo";
             break;
         default:
-            rn = "unknown sel";
             goto die;
         }
         break;
     case 29:
-//        gen_op_mfc0_taghi();
-        rn = "TagHi";
+        switch (sel) {
+        case 0:
+        case 2:
+        case 4:
+        case 6:
+            gen_op_mfc0_taghi();
+            rn = "TagHi";
+            break;
+        case 1:
+        case 3:
+        case 5:
+        case 7:
+            gen_op_mfc0_datahi();
+            rn = "DataHi";
+            break;
+        default:
+            goto die;
+        }
         break;
     case 30:
-        gen_op_mfc0_errorepc();
-        rn = "ErrorEPC";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_errorepc();
+           rn = "ErrorEPC";
+           break;
+        default:
+            goto die;
+        }
         break;
     case 31:
-        gen_op_mfc0_desave();
-        rn = "DESAVE";
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_desave(); /* EJTAG support */
+           rn = "DESAVE";
+           break;
+        default:
+            goto die;
+        }
         break;
     default:
-        rn = "unknown";
        goto die;
     }
 #if defined MIPS_DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM) {
-        fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
-                env->PC, rn, T0, reg, sel);
+        fprintf(logfile, "mfc0 %s (reg %d sel %d)\n",
+                rn, reg, sel);
     }
 #endif
     return;
@@ -1526,8 +2200,8 @@
 die:
 #if defined MIPS_DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM) {
-        fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
-                env->PC, rn, T0, reg, sel);
+        fprintf(logfile, "mfc0 %s (reg %d sel %d)\n",
+                rn, reg, sel);
     }
 #endif
     generate_exception(ctx, EXCP_RI);
@@ -1535,167 +2209,583 @@
 
 static void gen_mtc0 (DisasContext *ctx, int reg, int sel)
 {
-    const unsigned char *rn;
-    uint32_t val, old;
+    const char *rn = "invalid";
 
-    if (sel != 0 && reg != 16 && reg != 28) {
-        val = -1;
-        old = -1;
-        rn = "invalid";
-        goto die;
-    }
     switch (reg) {
     case 0:
-        gen_op_mtc0_index();
-        rn = "Index";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_index();
+            rn = "Index";
+            break;
+        case 1:
+//         gen_op_mtc0_mvpcontrol(); /* MT ASE */
+            rn = "MVPControl";
+//         break;
+        case 2:
+//         gen_op_mtc0_mvpconf0(); /* MT ASE */
+            rn = "MVPConf0";
+//         break;
+        case 3:
+//         gen_op_mtc0_mvpconf1(); /* MT ASE */
+            rn = "MVPConf1";
+//         break;
+        default:
+            goto die;
+        }
         break;
     case 1:
-// ignore or except?
-        rn = "Random";
+        switch (sel) {
+        case 0:
+           /* ignored */
+            rn = "Random";
+           break;
+        case 1:
+//         gen_op_mtc0_vpecontrol(); /* MT ASE */
+            rn = "VPEControl";
+//         break;
+        case 2:
+//         gen_op_mtc0_vpeconf0(); /* MT ASE */
+            rn = "VPEConf0";
+//         break;
+        case 3:
+//         gen_op_mtc0_vpeconf1(); /* MT ASE */
+            rn = "VPEConf1";
+//         break;
+        case 4:
+//         gen_op_mtc0_YQMask(); /* MT ASE */
+            rn = "YQMask";
+//         break;
+        case 5:
+//         gen_op_mtc0_vpeschedule(); /* MT ASE */
+            rn = "VPESchedule";
+//         break;
+        case 6:
+//         gen_op_mtc0_vpeschefback(); /* MT ASE */
+            rn = "VPEScheFBack";
+//         break;
+        case 7:
+//         gen_op_mtc0_vpeopt(); /* MT ASE */
+            rn = "VPEOpt";
+//         break;
+        default:
+            goto die;
+        }
         break;
     case 2:
-        gen_op_mtc0_entrylo0();
-        rn = "EntryLo0";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_entrylo0();
+           rn = "EntryLo0";
+           break;
+        case 1:
+//         gen_op_mtc0_tcstatus(); /* MT ASE */
+           rn = "TCStatus";
+//         break;
+        case 2:
+//         gen_op_mtc0_tcbind(); /* MT ASE */
+           rn = "TCBind";
+//         break;
+        case 3:
+//         gen_op_mtc0_tcrestart(); /* MT ASE */
+           rn = "TCRestart";
+//         break;
+        case 4:
+//         gen_op_mtc0_tchalt(); /* MT ASE */
+           rn = "TCHalt";
+//         break;
+        case 5:
+//         gen_op_mtc0_tccontext(); /* MT ASE */
+           rn = "TCContext";
+//         break;
+        case 6:
+//         gen_op_mtc0_tcschedule(); /* MT ASE */
+           rn = "TCSchedule";
+//         break;
+        case 7:
+//         gen_op_mtc0_tcschefback(); /* MT ASE */
+           rn = "TCScheFBack";
+//         break;
+        default:
+            goto die;
+        }
         break;
     case 3:
-        gen_op_mtc0_entrylo1();
-        rn = "EntryLo1";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_entrylo1();
+           rn = "EntryLo1";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 4:
-        gen_op_mtc0_context();
-        rn = "Context";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_context();
+           rn = "Context";
+           break;
+        case 1:
+//         gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */
+           rn = "ContextConfig";
+//         break;
+        default:
+            goto die;
+       }
         break;
     case 5:
-        gen_op_mtc0_pagemask();
-        rn = "PageMask";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_pagemask();
+           rn = "PageMask";
+           break;
+        case 1:
+           gen_op_mtc0_pagegrain();
+           rn = "PageGrain";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 6:
-        gen_op_mtc0_wired();
-        rn = "Wired";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_wired();
+           rn = "Wired";
+           break;
+        case 1:
+//         gen_op_mtc0_srsconf0(); /* shadow registers */
+           rn = "SRSConf0";
+//         break;
+        case 2:
+//         gen_op_mtc0_srsconf1(); /* shadow registers */
+           rn = "SRSConf1";
+//         break;
+        case 3:
+//         gen_op_mtc0_srsconf2(); /* shadow registers */
+           rn = "SRSConf2";
+//         break;
+        case 4:
+//         gen_op_mtc0_srsconf3(); /* shadow registers */
+           rn = "SRSConf3";
+//         break;
+        case 5:
+//         gen_op_mtc0_srsconf4(); /* shadow registers */
+           rn = "SRSConf4";
+//         break;
+        default:
+            goto die;
+       }
         break;
     case 7:
-// ignore or except?
-        rn = "Info";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_hwrena();
+           rn = "HWREna";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 8:
-// ignore or except?
+        /* ignored */
         rn = "BadVaddr";
         break;
     case 9:
-        gen_op_mtc0_count();
-        rn = "Count";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_count();
+           rn = "Count";
+           break;
+       /* 6,7 are implementation dependent */
+        default:
+            goto die;
+       }
+       /* Stop translation as we may have switched the execution mode */
+       ctx->bstate = BS_STOP;
         break;
     case 10:
-        gen_op_mtc0_entryhi();
-        rn = "EntryHi";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_entryhi();
+           rn = "EntryHi";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 11:
-        gen_op_mtc0_compare();
-        rn = "Compare";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_compare();
+           rn = "Compare";
+           break;
+       /* 6,7 are implementation dependent */
+        default:
+            goto die;
+       }
+       /* Stop translation as we may have switched the execution mode */
+       ctx->bstate = BS_STOP;
         break;
     case 12:
-        gen_op_mtc0_status();
-        rn = "Status";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_status();
+           rn = "Status";
+           break;
+        case 1:
+           gen_op_mtc0_intctl();
+           rn = "IntCtl";
+           break;
+        case 2:
+           gen_op_mtc0_srsctl();
+           rn = "SRSCtl";
+           break;
+        case 3:
+//         gen_op_mtc0_srsmap(); /* shadow registers */
+           rn = "SRSMap";
+//         break;
+        default:
+            goto die;
+       }
+       /* Stop translation as we may have switched the execution mode */
+       ctx->bstate = BS_STOP;
         break;
     case 13:
-        gen_op_mtc0_cause();
-        rn = "Cause";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_cause();
+           rn = "Cause";
+           break;
+        default:
+            goto die;
+       }
+       /* Stop translation as we may have switched the execution mode */
+       ctx->bstate = BS_STOP;
         break;
     case 14:
-        gen_op_mtc0_epc();
-        rn = "EPC";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_epc();
+           rn = "EPC";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 15:
-// ignore or except?
-        rn = "PRid";
+        switch (sel) {
+        case 0:
+           /* ignored */
+           rn = "PRid";
+           break;
+        case 1:
+           gen_op_mtc0_ebase();
+           rn = "EBase";
+           break;
+        default:
+            goto die;
+       }
         break;
     case 16:
         switch (sel) {
         case 0:
            gen_op_mtc0_config0();
-            rn = "Config0";
+            rn = "Config";
+            break;
+        case 1:
+           /* ignored */
+            rn = "Config1";
+            break;
+        case 2:
+           gen_op_mtc0_config2();
+            rn = "Config2";
+            break;
+        case 3:
+           /* ignored */
+            rn = "Config3";
             break;
+       /* 6,7 are implementation dependent */
         default:
             rn = "Invalid config selector";
             goto die;
         }
+       /* Stop translation as we may have switched the execution mode */
+       ctx->bstate = BS_STOP;
         break;
     case 17:
-// ignore or except?
-        rn = "LLaddr";
+        switch (sel) {
+        case 0:
+           /* ignored */
+           rn = "LLAddr";
+           break;
+        default:
+            goto die;
+        }
         break;
     case 18:
-        gen_op_mtc0_watchlo();
-        rn = "WatchLo";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_watchlo0();
+           rn = "WatchLo";
+           break;
+        case 1:
+//         gen_op_mtc0_watchlo1();
+           rn = "WatchLo1";
+//         break;
+        case 2:
+//         gen_op_mtc0_watchlo2();
+           rn = "WatchLo2";
+//         break;
+        case 3:
+//         gen_op_mtc0_watchlo3();
+           rn = "WatchLo3";
+//         break;
+        case 4:
+//         gen_op_mtc0_watchlo4();
+           rn = "WatchLo4";
+//         break;
+        case 5:
+//         gen_op_mtc0_watchlo5();
+           rn = "WatchLo5";
+//         break;
+        case 6:
+//         gen_op_mtc0_watchlo6();
+           rn = "WatchLo6";
+//         break;
+        case 7:
+//         gen_op_mtc0_watchlo7();
+           rn = "WatchLo7";
+//         break;
+        default:
+            goto die;
+        }
         break;
     case 19:
-        gen_op_mtc0_watchhi();
-        rn = "WatchHi";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_watchhi0();
+           rn = "WatchHi";
+           break;
+        case 1:
+//         gen_op_mtc0_watchhi1();
+           rn = "WatchHi1";
+//         break;
+        case 2:
+//         gen_op_mtc0_watchhi2();
+           rn = "WatchHi2";
+//         break;
+        case 3:
+//         gen_op_mtc0_watchhi3();
+           rn = "WatchHi3";
+//         break;
+        case 4:
+//         gen_op_mtc0_watchhi4();
+           rn = "WatchHi4";
+//         break;
+        case 5:
+//         gen_op_mtc0_watchhi5();
+           rn = "WatchHi5";
+//         break;
+        case 6:
+//         gen_op_mtc0_watchhi6();
+           rn = "WatchHi6";
+//         break;
+        case 7:
+//         gen_op_mtc0_watchhi7();
+           rn = "WatchHi7";
+//         break;
+        default:
+            goto die;
+        }
         break;
     case 20:
-       /* 64 bit only */
-//     gen_op_mtc0_xcontext();
-        rn = "XContext";
+        switch (sel) {
+        case 0:
+           /* 64 bit MMU only */
+           gen_op_mtc0_xcontext();
+           rn = "XContext";
+           break;
+        default:
+            goto die;
+        }
         break;
     case 21:
-//        gen_op_mtc0_framemask();
-        rn = "Framemask";
-       break;
+       /* Officially reserved, but sel 0 is used for R1x000 framemask */
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_framemask();
+           rn = "Framemask";
+           break;
+        default:
+            goto die;
+        }
+        break;
     case 22:
-// ignore or except?
-        rn = "Diagnostic";
+        /* ignored */
+        rn = "Diagnostic"; /* implementation dependent */
        break;
     case 23:
-        gen_op_mtc0_debug();
-        rn = "Debug";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_debug(); /* EJTAG support */
+           rn = "Debug";
+           break;
+        case 1:
+//         gen_op_mtc0_tracecontrol(); /* PDtrace support */
+           rn = "TraceControl";
+//         break;
+        case 2:
+//         gen_op_mtc0_tracecontrol2(); /* PDtrace support */
+           rn = "TraceControl2";
+//         break;
+        case 3:
+//         gen_op_mtc0_usertracedata(); /* PDtrace support */
+           rn = "UserTraceData";
+//         break;
+        case 4:
+//         gen_op_mtc0_debug(); /* PDtrace support */
+           rn = "TraceBPC";
+//         break;
+        default:
+            goto die;
+        }
+       /* Stop translation as we may have switched the execution mode */
+       ctx->bstate = BS_STOP;
         break;
     case 24:
-        gen_op_mtc0_depc();
-        rn = "DEPC";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_depc(); /* EJTAG support */
+           rn = "DEPC";
+           break;
+        default:
+            goto die;
+        }
         break;
     case 25:
-// ignore or except?
-        rn = "Performance";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_performance0();
+           rn = "Performance0";
+           break;
+        case 1:
+//         gen_op_mtc0_performance1();
+           rn = "Performance1";
+//         break;
+        case 2:
+//         gen_op_mtc0_performance2();
+           rn = "Performance2";
+//         break;
+        case 3:
+//         gen_op_mtc0_performance3();
+           rn = "Performance3";
+//         break;
+        case 4:
+//         gen_op_mtc0_performance4();
+           rn = "Performance4";
+//         break;
+        case 5:
+//         gen_op_mtc0_performance5();
+           rn = "Performance5";
+//         break;
+        case 6:
+//         gen_op_mtc0_performance6();
+           rn = "Performance6";
+//         break;
+        case 7:
+//         gen_op_mtc0_performance7();
+           rn = "Performance7";
+//         break;
+        default:
+            goto die;
+        }
        break;
     case 26:
-// ignore or except?
+       /* ignored */
         rn = "ECC";
        break;
     case 27:
-// ignore or except?
-        rn = "CacheErr";
+        switch (sel) {
+        case 0 ... 3:
+           /* ignored */
+           rn = "CacheErr";
+           break;
+        default:
+            goto die;
+        }
        break;
     case 28:
         switch (sel) {
         case 0:
+        case 2:
+        case 4:
+        case 6:
             gen_op_mtc0_taglo();
             rn = "TagLo";
             break;
+        case 1:
+        case 3:
+        case 5:
+        case 7:
+           gen_op_mtc0_datalo();
+            rn = "DataLo";
+            break;
         default:
-            rn = "invalid sel";
             goto die;
         }
         break;
     case 29:
-//     gen_op_mtc0_taghi();
-        rn = "TagHi";
+        switch (sel) {
+        case 0:
+        case 2:
+        case 4:
+        case 6:
+            gen_op_mtc0_taghi();
+            rn = "TagHi";
+            break;
+        case 1:
+        case 3:
+        case 5:
+        case 7:
+           gen_op_mtc0_datahi();
+            rn = "DataHi";
+            break;
+        default:
+            rn = "invalid sel";
+            goto die;
+        }
        break;
     case 30:
-        gen_op_mtc0_errorepc();
-        rn = "ErrorEPC";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_errorepc();
+           rn = "ErrorEPC";
+           break;
+        default:
+            goto die;
+        }
         break;
     case 31:
-        gen_op_mtc0_desave();
-        rn = "DESAVE";
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_desave(); /* EJTAG support */
+           rn = "DESAVE";
+           break;
+        default:
+            goto die;
+        }
+       /* Stop translation as we may have switched the execution mode */
+       ctx->bstate = BS_STOP;
         break;
     default:
-        rn = "unknown";
        goto die;
     }
 #if defined MIPS_DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM) {
-        fprintf(logfile, "%08x mtc0 %s => %08x (%d %d)\n",
-                env->PC, rn, T0, reg, sel);
+        fprintf(logfile, "mtc0 %s (reg %d sel %d)\n",
+                rn, reg, sel);
     }
 #endif
     return;
@@ -1703,16 +2793,16 @@
 die:
 #if defined MIPS_DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM) {
-        fprintf(logfile, "%08x mtc0 %s => %08x (%d %d)\n",
-                env->PC, rn, T0, reg, sel);
+        fprintf(logfile, "mtc0 %s (reg %d sel %d)\n",
+                rn, reg, sel);
     }
 #endif
     generate_exception(ctx, EXCP_RI);
 }
 
-static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
+static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd)
 {
-    const unsigned char *opn = "unk";
+    const char *opn = "unk";
 
     if (!(ctx->CP0_Status & (1 << CP0St_CU0)) &&
         (ctx->hflags & MIPS_HFLAG_UM) &&
@@ -1721,7 +2811,7 @@
         if (loglevel & CPU_LOG_TB_IN_ASM) {
             fprintf(logfile, "CP0 is not usable\n");
         }
-        generate_exception_err (ctx, EXCP_CpU, 0);
+        generate_exception (ctx, EXCP_CpU);
         return;
     }
 
@@ -1737,13 +2827,12 @@
         break;
     case OPC_MTC0:
         /* If we get an exception, we want to restart at next instruction */
+       /* XXX: breaks for mtc in delay slot */
         ctx->pc += 4;
         save_cpu_state(ctx, 1);
         ctx->pc -= 4;
         GEN_LOAD_REG_TN(T0, rt);
         gen_mtc0(ctx, rd, ctx->opcode & 0x7);
-        /* Stop translation as we may have switched the execution mode */
-        ctx->bstate = BS_STOP;
         opn = "mtc0";
         break;
 #if defined(MIPS_USES_R4K_TLB)
@@ -1801,31 +2890,30 @@
     MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
 }
 
-#ifdef MIPS_USES_FPU
 /* CP1 Branches (before delay slot) */
-static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond,
+static void gen_compute_branch1 (DisasContext *ctx, uint32_t op,
                                  int32_t offset)
 {
     target_ulong btarget;
 
     btarget = ctx->pc + 4 + offset;
 
-    switch (cond) {
-    case 0x0000: /* bc1f */
+    switch (op) {
+    case OPC_BC1F:
         gen_op_bc1f();
         MIPS_DEBUG("bc1f %08x", btarget);
         goto not_likely;
-    case 0x0002: /* bc1fl */
+    case OPC_BC1FL:
         gen_op_bc1f();
         MIPS_DEBUG("bc1fl %08x", btarget);
         goto likely;
-    case 0x0001: /* bc1t */
+    case OPC_BC1T:
         gen_op_bc1t();
         MIPS_DEBUG("bc1t %08x", btarget);
     not_likely:
         ctx->hflags |= MIPS_HFLAG_BC;
         break;
-    case 0x0003: /* bc1tl */
+    case OPC_BC1TL:
         gen_op_bc1t();
         MIPS_DEBUG("bc1tl %08x", btarget);
     likely:
@@ -1833,7 +2921,7 @@
         break;
     default:    
         MIPS_INVAL("cp1 branch/jump");
-        generate_exception(ctx, EXCP_RI);
+        generate_exception_err (ctx, EXCP_RI, 1);
         return;
     }
     gen_op_set_bcond();
@@ -1846,9 +2934,9 @@
 }
 
 /* Coprocessor 1 (FPU) */
-static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs)
+static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
 {
-    const unsigned char *opn = "unk";
+    const char *opn = "unk";
 
     switch (opc) {
     case OPC_MFC1:
@@ -1866,7 +2954,7 @@
     case OPC_CFC1:
         if (fs != 0 && fs != 31) {
             MIPS_INVAL("cfc1 freg");
-            generate_exception(ctx, EXCP_RI);
+            generate_exception_err (ctx, EXCP_RI, 1);
             return;
         }
         GEN_LOAD_IMM_TN(T1, fs);
@@ -1875,9 +2963,9 @@
         opn = "cfc1";
         break;
     case OPC_CTC1:
-        if (fs != 0 && fs != 31) {
+         if (fs != 0 && fs != 31) {
             MIPS_INVAL("ctc1 freg");
-            generate_exception(ctx, EXCP_RI);
+            generate_exception_err (ctx, EXCP_RI, 1);
             return;
         }
         GEN_LOAD_IMM_TN(T1, fs);
@@ -1891,7 +2979,7 @@
                     ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
                     ((ctx->opcode >> 16) & 0x1F));
         }
-        generate_exception(ctx, EXCP_RI);
+        generate_exception_err (ctx, EXCP_RI, 1);
         return;
     }
     MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
@@ -1909,16 +2997,16 @@
  */
 #define CHECK_FR(ctx, freg) do { \
         if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \
-            generate_exception(ctx, EXCP_RI); \
+            generate_exception_err (ctx, EXCP_RI, 1); \
             return; \
         } \
     } while(0)
 
 #define FOP(func, fmt) (((fmt) << 21) | (func))
 
-static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, 
int func)
+static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int 
fd)
 {
-    const unsigned char *opn = "unk";
+    const char *opn = "unk";
     const char *condnames[] = {
             "c.f",
             "c.un",
@@ -1938,7 +3026,8 @@
             "c.ngt",
     };
     int binary = 0;
-    
+    uint32_t func = ctx->opcode & 0x3f;
+
     switch (ctx->opcode & FOP(0x3f, 0x1f)) {
     case FOP(0, 17):
         CHECK_FR(ctx, fs | ft | fd);
@@ -2034,7 +3123,7 @@
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_floorw_d();
         GEN_STORE_FTN_FREG(fd, WT2);
-        opn = "ceil.w.d";
+        opn = "floor.w.d";
         break;
     case FOP(33, 16): /* cvt.d.s */
         CHECK_FR(ctx, fs | fd);
@@ -2202,11 +3291,11 @@
         break;
     default:    
         if (loglevel & CPU_LOG_TB_IN_ASM) {
-            fprintf(logfile, "Invalid arith function: %08x %03x %03x %03x\n",
+            fprintf(logfile, "Invalid FP arith function: %08x %03x %03x 
%03x\n",
                     ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
                     ((ctx->opcode >> 16) & 0x1F));
         }
-        generate_exception(ctx, EXCP_RI);
+        generate_exception_err (ctx, EXCP_RI, 1);
         return;
     }
     if (binary)
@@ -2214,14 +3303,27 @@
     else
         MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
 }
-#endif
 
-/* ISA extensions */
+static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
+{
+    uint32_t ccbit;
+
+    if (cc)
+        ccbit = 1 << (24 + cc);
+    else
+        ccbit = 1 << 23;
+    if (!tf)
+        gen_op_movf(ccbit, rd, rs);
+    else
+       gen_op_movt(ccbit, rd, rs);
+}
+
+/* ISA extensions (ASEs) */
 /* MIPS16 extension to MIPS32 */
 /* SmartMIPS extension to MIPS32 */
 
-#ifdef TARGET_MIPS64
-static void gen_arith64 (DisasContext *ctx, uint16_t opc)
+#ifdef MIPS_HAS_MIPS64
+static void gen_arith64 (DisasContext *ctx, uint32_t opc)
 {
     if (func == 0x02 && rd == 0) {
         /* NOP */
@@ -2266,7 +3368,7 @@
 {
     int32_t offset;
     int rs, rt, rd, sa;
-    uint16_t op, op1;
+    uint32_t op, op1, op2;
     int16_t imm;
 
     /* make sure instructions are on a word boundary */
@@ -2280,76 +3382,86 @@
         MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
         gen_blikely(ctx);
     }
-    op = ctx->opcode >> 26;
-    rs = ((ctx->opcode >> 21) & 0x1F);
-    rt = ((ctx->opcode >> 16) & 0x1F);
-    rd = ((ctx->opcode >> 11) & 0x1F);
-    sa = ((ctx->opcode >> 6) & 0x1F);
+    op = MASK_OP_MAJOR(ctx->opcode);
+    rs = (ctx->opcode >> 21) & 0x1f;
+    rt = (ctx->opcode >> 16) & 0x1f;
+    rd = (ctx->opcode >> 11) & 0x1f;
+    sa = (ctx->opcode >> 6) & 0x1f;
     imm = (int16_t)ctx->opcode;
     switch (op) {
-    case 0x00:          /* Special opcode */
-        op1 = ctx->opcode & 0x3F;
+    case OPC_SPECIAL:
+        op1 = MASK_SPECIAL(ctx->opcode);
         switch (op1) {
-        case 0x00:          /* Arithmetic with immediate */
-        case 0x02 ... 0x03:
-            gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa);
-            break;
-        case 0x04:          /* Arithmetic */
-        case 0x06 ... 0x07:
-        case 0x0A ... 0x0B:
-        case 0x20 ... 0x27:
-        case 0x2A ... 0x2B:
-            gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
+        case OPC_SLL:          /* Arithmetic with immediate */
+        case OPC_SRL ... OPC_SRA:
+            gen_arith_imm(ctx, op1, rd, rt, sa);
+            break;
+        case OPC_SLLV:         /* Arithmetic */
+        case OPC_SRLV ... OPC_SRAV:
+        case OPC_MOVZ ... OPC_MOVN:
+        case OPC_ADD ... OPC_NOR:
+        case OPC_SLT ... OPC_SLTU:
+            gen_arith(ctx, op1, rd, rs, rt);
             break;
-        case 0x18 ... 0x1B: /* MULT / DIV */
-            gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
+        case OPC_MULT ... OPC_DIVU:
+            gen_muldiv(ctx, op1, rs, rt);
             break;
-        case 0x08 ... 0x09: /* Jumps */
-            gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
+        case OPC_JR ... OPC_JALR:
+            gen_compute_branch(ctx, op1, rs, rd, sa);
             return;
-        case 0x30 ... 0x34: /* Traps */
-        case 0x36:
-            gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1);
-            break;
-        case 0x10:          /* Move from HI/LO */
-        case 0x12:
-            gen_HILO(ctx, op1 | EXT_SPECIAL, rd);
-            break;
-        case 0x11:
-        case 0x13:          /* Move to HI/LO */
-            gen_HILO(ctx, op1 | EXT_SPECIAL, rs);
+        case OPC_TGE ... OPC_TEQ: /* Traps */
+        case OPC_TNE:
+            gen_trap(ctx, op1, rs, rt, -1);
+            break;
+        case OPC_MFHI:          /* Move from HI/LO */
+        case OPC_MFLO:
+            gen_HILO(ctx, op1, rd);
+            break;
+        case OPC_MTHI:
+        case OPC_MTLO:          /* Move to HI/LO */
+            gen_HILO(ctx, op1, rs);
+            break;
+        case OPC_PMON:          /* Pmon entry point */
+            gen_op_pmon(sa);
             break;
-        case 0x0C:          /* SYSCALL */
+        case OPC_SYSCALL:
             generate_exception(ctx, EXCP_SYSCALL);
+            ctx->bstate = BS_EXCP;
             break;
-        case 0x0D:          /* BREAK */
+        case OPC_BREAK:
             generate_exception(ctx, EXCP_BREAK);
             break;
-        case 0x0F:          /* SYNC */
-            /* Treat as a noop */
+        case OPC_SPIM:        /* SPIM ? */
+           /* Implemented as RI exception for now. */
+            MIPS_INVAL("spim (unofficial)");
+            generate_exception(ctx, EXCP_RI);
             break;
-        case 0x05:          /* Pmon entry point */
-            gen_op_pmon((ctx->opcode >> 6) & 0x1F);
+        case OPC_SYNC:
+            /* Treat as a noop. */
             break;
 
-        case 0x01:          /* MOVCI */
-#if defined (MIPS_HAS_MOVCI)
-            /* XXX */
-#else
-            /* Not implemented */
-            generate_exception_err (ctx, EXCP_CpU, 1);
-#endif
+        case OPC_MOVCI:
+            gen_op_cp1_enabled();
+            gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
+                      (ctx->opcode >> 16) & 1);
+            break;
+
+#ifdef MIPS_HAS_MIPS64
+       /* MIPS64 specific opcodes */
+        case OPC_DSLL:
+        case OPC_DSRL ... OPC_DSRA:
+        case OPC_DSLL32:
+        case OPC_DSRL32 ... OPC_DSRA32:
+            gen_arith_imm(ctx, op1, rd, rt, sa);
+            break;
+        case OPC_DSLLV:
+        case OPC_DSRLV ... OPC_DSRAV:
+        case OPC_DADD ... OPC_DSUBU:
+            gen_arith(ctx, op1, rd, rs, rt);
+            break;
+        case OPC_DMULT ... OPC_DDIVU:
+            gen_muldiv(ctx, op1, rs, rt);
             break;
-
-#if defined (TARGET_MIPS64)
-        case 0x14: /* MIPS64 specific opcodes */
-        case 0x16:
-        case 0x17:
-        case 0x1C ... 0x1F:
-        case 0x2C ... 0x2F:
-        case 0x37:
-        case 0x39 ... 0x3B:
-        case 0x3E ... 0x3F:
 #endif
         default:            /* Invalid */
             MIPS_INVAL("special");
@@ -2357,23 +3469,20 @@
             break;
         }
         break;
-    case 0x1C:          /* Special2 opcode */
-        op1 = ctx->opcode & 0x3F;
+    case OPC_SPECIAL2:
+        op1 = MASK_SPECIAL2(ctx->opcode);
         switch (op1) {
-#if defined (MIPS_USES_R4K_EXT)
-        /* Those instructions are not part of MIPS32 core */
-        case 0x00 ... 0x01: /* Multiply and add/sub */
-        case 0x04 ... 0x05:
-            gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
+        case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
+        case OPC_MSUB ... OPC_MSUBU:
+            gen_muldiv(ctx, op1, rs, rt);
             break;
-        case 0x02:          /* MUL */
-            gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
+        case OPC_MUL:
+            gen_arith(ctx, op1, rd, rs, rt);
             break;
-        case 0x20 ... 0x21: /* CLO / CLZ */
-            gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
+        case OPC_CLZ ... OPC_CLO:
+            gen_cl(ctx, op1, rd, rs);
             break;
-#endif
-        case 0x3F:          /* SDBBP */
+        case OPC_SDBBP:
             /* XXX: not clear which exception should be raised
              *      when in debug mode...
              */
@@ -2384,22 +3493,109 @@
             }
             /* Treat as a noop */
             break;
+#ifdef MIPS_HAS_MIPS64
+        case OPC_DCLZ ... OPC_DCLO:
+            gen_cl(ctx, op1, rd, rs);
+            break;
+#endif
         default:            /* Invalid */
             MIPS_INVAL("special2");
             generate_exception(ctx, EXCP_RI);
             break;
         }
         break;
-    case 0x01:          /* B REGIMM opcode */
-        op1 = ((ctx->opcode >> 16) & 0x1F);
+    case OPC_SPECIAL3:
+        op1 = MASK_SPECIAL3(ctx->opcode);
+        switch (op1) {
+        case OPC_EXT:
+        case OPC_INS:
+            gen_bitops(ctx, op1, rt, rs, sa, rd);
+            break;
+        case OPC_BSHFL:
+            op2 = MASK_BSHFL(ctx->opcode);
+            switch (op2) {
+            case OPC_WSBH:
+                GEN_LOAD_REG_TN(T1, rt);
+                gen_op_wsbh();
+                break;
+            case OPC_SEB:
+                GEN_LOAD_REG_TN(T1, rt);
+                gen_op_seb();
+                break;
+            case OPC_SEH:
+                GEN_LOAD_REG_TN(T1, rt);
+                gen_op_seh();
+                break;
+             default:            /* Invalid */
+                MIPS_INVAL("bshfl");
+                generate_exception(ctx, EXCP_RI);
+                break;
+           }
+           GEN_STORE_TN_REG(rd, T0);
+           break;
+       case OPC_RDHWR:
+           switch (rd) {
+           case 0:
+               gen_op_rdhwr_cpunum();
+               break;
+           case 1:
+               gen_op_rdhwr_synci_step();
+               break;
+           case 2:
+               gen_op_rdhwr_cc();
+               break;
+           case 3:
+               gen_op_rdhwr_ccres();
+               break;
+           default:            /* Invalid */
+               MIPS_INVAL("rdhwr");
+               generate_exception(ctx, EXCP_RI);
+               break;
+           }
+           GEN_STORE_TN_REG(rt, T0);
+           break;
+#ifdef MIPS_HAS_MIPS64
+       case OPC_DEXTM ... OPC_DEXT:
+       case OPC_DINSM ... OPC_DINS:
+           gen_bitops(ctx, op1, rt, rs, sa, rd);
+            break;
+       case OPC_DBSHFL:
+           op2 = MASK_DBSHFL(ctx->opcode);
+           switch (op2) {
+           case OPC_DSBH:
+               GEN_LOAD_REG_TN(T1, rt);
+               gen_op_dsbh();
+               break;
+           case OPC_DSHD:
+               GEN_LOAD_REG_TN(T1, rt);
+               gen_op_dshd();
+               break;
+            default:            /* Invalid */
+                MIPS_INVAL("dbshfl");
+                generate_exception(ctx, EXCP_RI);
+                break;
+           }
+           GEN_STORE_TN_REG(rd, T0);
+#endif
+        default:            /* Invalid */
+            MIPS_INVAL("special3");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_REGIMM:
+        op1 = MASK_REGIMM(ctx->opcode);
         switch (op1) {
-        case 0x00 ... 0x03: /* REGIMM branches */
-        case 0x10 ... 0x13:
-            gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2);
+        case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
+        case OPC_BLTZAL ... OPC_BGEZALL:
+            gen_compute_branch(ctx, op1, rs, -1, imm << 2);
             return;
-        case 0x08 ... 0x0C: /* Traps */
-        case 0x0E:
-            gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm);
+        case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
+        case OPC_TNEI:
+            gen_trap(ctx, op1, rs, -1, imm);
+            break;
+        case OPC_SYNCI:
+           /* treat as noop */
             break;
         default:            /* Invalid */
             MIPS_INVAL("REGIMM");
@@ -2407,48 +3603,78 @@
             break;
         }
         break;
-    case 0x10:          /* CP0 opcode */
-        op1 = ((ctx->opcode >> 21) & 0x1F);
+    case OPC_CP0:
+        op1 = MASK_CP0(ctx->opcode);
         switch (op1) {
-        case 0x00:
-        case 0x04:
-            gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
+        case OPC_MFC0:
+        case OPC_MTC0:
+#ifdef MIPS_HAS_MIPS64
+        case OPC_DMFC0:
+        case OPC_DMTC0:
+#endif
+            gen_cp0(ctx, op1, rt, rd);
+            break;
+        case OPC_C0_FIRST ... OPC_C0_LAST:
+            gen_cp0(ctx, MASK_C0(ctx->opcode), rt, rd);
+            break;
+        case OPC_MFMC0:
+            op2 = MASK_MFMC0(ctx->opcode);
+            switch (op2) {
+            case OPC_DI:
+                gen_op_di();
+                /* Stop translation as we may have switched the execution mode 
*/
+                ctx->bstate = BS_STOP;
+                break;
+            case OPC_EI:
+                gen_op_ei();
+                /* Stop translation as we may have switched the execution mode 
*/
+                ctx->bstate = BS_STOP;
+                break;
+            default:            /* Invalid */
+                MIPS_INVAL("MFMC0");
+                generate_exception(ctx, EXCP_RI);
+                break;
+            }
+            GEN_STORE_TN_REG(rt, T0);
             break;
+        /* Shadow registers (not implemented). */
+        case OPC_RDPGPR:
+        case OPC_WRPGPR:
         default:
-            gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd);
+            generate_exception(ctx, EXCP_RI);
             break;
         }
         break;
-    case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
-        gen_arith_imm(ctx, op, rt, rs, imm);
-        break;
-    case 0x02 ... 0x03: /* Jump */
-        offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
-        gen_compute_branch(ctx, op, rs, rt, offset);
-        return;
-    case 0x04 ... 0x07: /* Branch */
-    case 0x14 ... 0x17:
-        gen_compute_branch(ctx, op, rs, rt, imm << 2);
-        return;
-    case 0x20 ... 0x2E: /* Load and stores */
-    case 0x30:
-    case 0x38:
-        gen_ldst(ctx, op, rt, rs, imm);
-        break;
-    case 0x2F:          /* Cache operation */
-        /* Treat as a noop */
-        break;
-    case 0x33:          /* Prefetch */
+    case OPC_ADDI ... OPC_LUI: /* Arithmetic with immediate opcode */
+         gen_arith_imm(ctx, op, rt, rs, imm);
+         break;
+    case OPC_J ... OPC_JAL: /* Jump */
+         offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
+         gen_compute_branch(ctx, op, rs, rt, offset);
+         return;
+    case OPC_BEQ ... OPC_BGTZ: /* Branch */
+    case OPC_BEQL ... OPC_BGTZL:
+         gen_compute_branch(ctx, op, rs, rt, imm << 2);
+         return;
+    case OPC_LB ... OPC_LWR: /* Load and stores */
+    case OPC_SB ... OPC_SW:
+    case OPC_SWR:
+    case OPC_LL:
+    case OPC_SC:
+         gen_ldst(ctx, op, rt, rs, imm);
+         break;
+    case OPC_CACHE:
+         /* Treat as a noop */
+         break;
+    case OPC_PREF:
         /* Treat as a noop */
         break;
-    case 0x3F: /* HACK */
-        break;
 
     /* Floating point.  */
-    case 0x31: /* LWC1 */
-    case 0x35: /* LDC1 */
-    case 0x39: /* SWC1 */
-    case 0x3D: /* SDC1 */
+    case OPC_LWC1:
+    case OPC_LDC1:
+    case OPC_SWC1:
+    case OPC_SDC1:
 #if defined(MIPS_USES_FPU)
         save_cpu_state(ctx, 1);
         gen_op_cp1_enabled();
@@ -2458,65 +3684,80 @@
 #endif
         break;
 
-    case 0x11:          /* CP1 opcode */
+    case OPC_CP1:
 #if defined(MIPS_USES_FPU)
         save_cpu_state(ctx, 1);
         gen_op_cp1_enabled();
-        op1 = ((ctx->opcode >> 21) & 0x1F);
+        op1 = MASK_CP1(ctx->opcode);
         switch (op1) {
-        case 0x00: /* mfc1 */
-        case 0x02: /* cfc1 */
-        case 0x04: /* mtc1 */
-        case 0x06: /* ctc1 */
-            gen_cp1(ctx, op1 | EXT_CP1, rt, rd);
+        case OPC_MFC1:
+        case OPC_CFC1:
+        case OPC_MTC1:
+        case OPC_CTC1:
+            gen_cp1(ctx, op1, rt, rd);
             break;
-        case 0x08: /* bc */
-            gen_compute_branch1(ctx, rt, imm << 2);
+        case OPC_BC1:
+            gen_compute_branch1(ctx, MASK_CP1_BCOND(ctx->opcode), imm << 2);
             return;
-        case 0x10: /* 16: fmt=single fp */
-        case 0x11: /* 17: fmt=double fp */
-        case 0x14: /* 20: fmt=32bit fixed */
-        case 0x15: /* 21: fmt=64bit fixed */
-            gen_farith(ctx, op1, rt, rd, sa, ctx->opcode & 0x3f);
+        case OPC_S_FMT:
+        case OPC_D_FMT:
+        case OPC_W_FMT:
+        case OPC_L_FMT:
+            gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa);
             break;
         default:
             generate_exception_err(ctx, EXCP_RI, 1);
             break;
         }
-        break;
 #else
         generate_exception_err(ctx, EXCP_CpU, 1);
 #endif
         break;
 
     /* COP2.  */
-    case 0x32: /* LWC2 */
-    case 0x36: /* LDC2 */
-    case 0x3A: /* SWC2 */
-    case 0x3E: /* SDC2 */
-    case 0x12:          /* CP2 opcode */
-        /* Not implemented */
+    case OPC_LWC2:
+    case OPC_LDC2:
+    case OPC_SWC2:
+    case OPC_SDC2:
+    case OPC_CP2:
+        /* COP2: Not implemented. */
         generate_exception_err(ctx, EXCP_CpU, 2);
         break;
 
-    case 0x13:          /* CP3 opcode */
+    case OPC_CP3:
+        gen_op_cp1_enabled();
+        op1 = MASK_CP3(ctx->opcode);
+        switch (op1) {
         /* Not implemented */
-        generate_exception_err(ctx, EXCP_CpU, 3);
+        default:
+            generate_exception_err(ctx, EXCP_RI, 1);
+            break;
+        }
         break;
 
-#if defined (TARGET_MIPS64)
-    case 0x18 ... 0x1B:
-    case 0x27:
-    case 0x34:
-    case 0x37:
-        /* MIPS64 opcodes */
-#endif
-#if defined (MIPS_HAS_JALX)
-    case 0x1D:
-        /* JALX: not implemented */
+#ifdef MIPS_HAS_MIPS64
+    /* MIPS64 opcodes */
+    case OPC_LWU:
+    case OPC_LDL ... OPC_LDR:
+    case OPC_SDL ... OPC_SDR:
+    case OPC_LLD:
+    case OPC_LD:
+    case OPC_SCD:
+    case OPC_SD:
+        gen_ldst(ctx, op, rt, rs, imm);
+        break;
+    case OPC_DADDI ... OPC_DADDIU:
+        gen_arith_imm(ctx, op, rt, rs, imm);
+        break;
+#endif
+#ifdef MIPS_HAS_MIPS16
+    case OPC_JALX:
+        /* MIPS16: Not implemented. */
+#endif
+#ifdef MIPS_HAS_MDMX
+    case OPC_MDMX:
+        /* MDMX: Not implemented. */
 #endif
-    case 0x1E:
-        /* ASE specific */
     default:            /* Invalid */
         MIPS_INVAL("");
         generate_exception(ctx, EXCP_RI);
@@ -2708,7 +3949,6 @@
     return gen_intermediate_code_internal(env, tb, 1);
 }
 
-#ifdef MIPS_USES_FPU
 void fpu_dump_state(CPUState *env, FILE *f, 
                     int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
@@ -2722,19 +3962,19 @@
 
     fpu_fprintf(f, "CP1 FCR0 0x%08x  FCR31 0x%08x  SR.FR %d\n",
                 env->fcr0, env->fcr31,
-                (env->CP0_Status & (1<<CP0St_FR)) != 0);
+                (env->CP0_Status & (1 << CP0St_FR)) != 0);
     fpu_fprintf(f, "FT0: "); printfpr(&env->ft0);
     fpu_fprintf(f, "FT1: "); printfpr(&env->ft1);
     fpu_fprintf(f, "FT2: "); printfpr(&env->ft2);
-    for(i=0; i < 32; i+=2) {
-        fpu_fprintf(f, "f%02d: ", i);
+    for(i = 0; i < 32; i += 2) {
+        fpu_fprintf(f, "%s: ", fregnames[i]);
         printfpr(FPR(env, i));
     }
 
 #undef printfpr
 }
 
-void dump_fpu(CPUState *env)
+void dump_fpu (CPUState *env)
 {
     if (loglevel) { 
        fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
@@ -2742,7 +3982,6 @@
        fpu_dump_state(env, logfile, fprintf, 0);
     }
 }
-#endif /* MIPS_USES_FPU */
 
 void cpu_dump_state (CPUState *env, FILE *f, 
                      int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
@@ -2773,9 +4012,8 @@
                 c0_status, env->CP0_Cause, env->CP0_EPC);
     cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
                 env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
-#ifdef MIPS_USES_FPU
-    fpu_dump_state(env, f, cpu_fprintf, flags);
-#endif
+    if (c0_status & (1 << CP0St_CU1))
+        fpu_dump_state(env, f, cpu_fprintf, flags);
 }
 
 CPUMIPSState *cpu_mips_init (void)
@@ -2803,16 +4041,12 @@
     env->tlb_in_use = MIPS_TLB_NB;
 #endif
     env->CP0_Wired = 0;
+    /* SMP not implemented */
+    env->CP0_EBase = 0x80000000;
     env->CP0_Config0 = MIPS_CONFIG0;
-#if defined (MIPS_CONFIG1)
-        env->CP0_Config1 = MIPS_CONFIG1;
-#endif
-#if defined (MIPS_CONFIG2)
-        env->CP0_Config2 = MIPS_CONFIG2;
-#endif
-#if defined (MIPS_CONFIG3)
-        env->CP0_Config3 = MIPS_CONFIG3;
-#endif
+    env->CP0_Config1 = MIPS_CONFIG1;
+    env->CP0_Config2 = MIPS_CONFIG2;
+    env->CP0_Config3 = MIPS_CONFIG3;
     env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
     env->CP0_WatchLo = 0;
     env->hflags = MIPS_HFLAG_ERL;
@@ -2826,4 +4060,7 @@
 #ifdef MIPS_USES_FPU
     env->fcr0 = MIPS_FCR0;     
 #endif
+    /* XXX some guesswork here, values are CPU specific */
+    env->SYNCI_Step = 16;
+    env->CCRes = 2;
 }




reply via email to

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