Per-CPU instruction decoding implementation, by Aurelien Jarno.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3228 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index f8b4b18..f8299ad 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -441,6 +441,7 @@
     int CCRes; /* Cycle count resolution/divisor */
     uint32_t CP0_Status_rw_bitmask; /* Read/write bits in CP0_Status */
     uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */
+    int insn_flags; /* Supported instruction set */
 
 #ifdef CONFIG_USER_ONLY
     target_ulong tls_value;
diff --git a/target-mips/helper.c b/target-mips/helper.c
index 6310d68..d0e5b1d 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -369,8 +369,7 @@
         }
     enter_debug_mode:
         env->hflags |= MIPS_HFLAG_DM;
-        if ((env->CP0_Config0 & (0x3 << CP0C0_AT)))
-            env->hflags |= MIPS_HFLAG_64;
+        env->hflags |= MIPS_HFLAG_64;
         env->hflags &= ~MIPS_HFLAG_UM;
         /* EJTAG probe trap enable is not implemented... */
         if (!(env->CP0_Status & (1 << CP0St_EXL)))
@@ -396,8 +395,7 @@
             env->CP0_ErrorEPC = env->PC[env->current_tc];
         }
         env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
-        if ((env->CP0_Config0 & (0x3 << CP0C0_AT)))
-            env->hflags |= MIPS_HFLAG_64;
+        env->hflags |= MIPS_HFLAG_64;
         env->hflags &= ~MIPS_HFLAG_UM;
         if (!(env->CP0_Status & (1 << CP0St_EXL)))
             env->CP0_Cause &= ~(1 << CP0Ca_BD);
@@ -499,8 +497,7 @@
                 env->CP0_Cause &= ~(1 << CP0Ca_BD);
             }
             env->CP0_Status |= (1 << CP0St_EXL);
-            if ((env->CP0_Config0 & (0x3 << CP0C0_AT)))
-                env->hflags |= MIPS_HFLAG_64;
+            env->hflags |= MIPS_HFLAG_64;
             env->hflags &= ~MIPS_HFLAG_UM;
         }
         env->hflags &= ~MIPS_HFLAG_BMASK;
diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h
index 6f012a9..a796c7e 100644
--- a/target-mips/mips-defs.h
+++ b/target-mips/mips-defs.h
@@ -14,6 +14,41 @@
 #define TARGET_LONG_BITS 32
 #endif
 
+/* Masks used to mark instructions to indicate which ISA level they
+   were introduced in. */
+#define		ISA_MIPS1	0x00000001
+#define		ISA_MIPS2	0x00000002
+#define		ISA_MIPS3	0x00000004
+#define		ISA_MIPS4	0x00000008
+#define		ISA_MIPS5	0x00000010
+#define		ISA_MIPS32	0x00000020
+#define		ISA_MIPS32R2	0x00000040
+#define		ISA_MIPS64	0x00000080
+#define		ISA_MIPS64R2	0x00000100
+
+/* MIPS ASE */
+#define		ASE_MIPS16	0x00001000
+#define		ASE_MIPS3D	0x00002000
+#define		ASE_MDMX	0x00004000
+#define		ASE_DSP		0x00008000
+#define		ASE_DSPR2	0x00010000
+
+/* Chip specific instructions.   */
+/* Currently void */
+
+/* MIPS CPU defines.  */
+#define		CPU_MIPS1	(ISA_MIPS1)
+#define		CPU_MIPS2	(CPU_MIPS1 | ISA_MIPS2)
+#define		CPU_MIPS3	(CPU_MIPS2 | ISA_MIPS3)
+#define		CPU_MIPS4	(CPU_MIPS3 | ISA_MIPS4)
+#define		CPU_MIPS5	(CPU_MIPS4 | ISA_MIPS5)
+
+#define		CPU_MIPS32	(CPU_MIPS2 | ISA_MIPS32)
+#define		CPU_MIPS64	(CPU_MIPS5 | CPU_MIPS32 | ISA_MIPS64)
+
+#define		CPU_MIPS32R2	(CPU_MIPS32 | ISA_MIPS32R2)
+#define		CPU_MIPS64R2	(CPU_MIPS64 | CPU_MIPS32R2 | ISA_MIPS64R2)
+
 /* Strictly follow the architecture standard:
    - Disallow "special" instruction handling for PMON/SPIM.
    Note that we still maintain Count/Compare to match the host clock. */
diff --git a/target-mips/op.c b/target-mips/op.c
index 8d4c7d4..dd90163 100644
--- a/target-mips/op.c
+++ b/target-mips/op.c
@@ -1847,10 +1847,9 @@
         (val & (1 << CP0St_UM)))
         env->hflags |= MIPS_HFLAG_UM;
 #ifdef TARGET_MIPS64
-    if (!(env->CP0_Config0 & (0x3 << CP0C0_AT)) ||
-        ((env->hflags & MIPS_HFLAG_UM) &&
+    if  ((env->hflags & MIPS_HFLAG_UM) &&
         !(val & (1 << CP0St_PX)) &&
-        !(val & (1 << CP0St_UX))))
+        !(val & (1 << CP0St_UX)))
         env->hflags &= ~MIPS_HFLAG_64;
 #endif
     if (val & (1 << CP0St_CU1))
@@ -1906,7 +1905,7 @@
 {
     uint32_t mask = 0x00C00300;
 
-    if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
+    if (env->insn_flags & ISA_MIPS32R2)
         mask |= 1 << CP0Ca_DC;
 
     env->CP0_Cause = (env->CP0_Cause & ~mask) | (T0 & mask);
@@ -3014,10 +3013,9 @@
         (env->CP0_Status & (1 << CP0St_UM)))
         env->hflags |= MIPS_HFLAG_UM;
 #ifdef TARGET_MIPS64
-    if (!(env->CP0_Config0 & (0x3 << CP0C0_AT)) ||
-        ((env->hflags & MIPS_HFLAG_UM) &&
+     if ((env->hflags & MIPS_HFLAG_UM) &&
         !(env->CP0_Status & (1 << CP0St_PX)) &&
-        !(env->CP0_Status & (1 << CP0St_UX))))
+        !(env->CP0_Status & (1 << CP0St_UX)))
         env->hflags &= ~MIPS_HFLAG_64;
 #endif
     if (loglevel & CPU_LOG_EXEC)
@@ -3038,10 +3036,9 @@
         (env->CP0_Status & (1 << CP0St_UM)))
         env->hflags |= MIPS_HFLAG_UM;
 #ifdef TARGET_MIPS64
-    if (!(env->CP0_Config0 & (0x3 << CP0C0_AT)) ||
-        ((env->hflags & MIPS_HFLAG_UM) &&
+    if ((env->hflags & MIPS_HFLAG_UM) &&
         !(env->CP0_Status & (1 << CP0St_PX)) &&
-        !(env->CP0_Status & (1 << CP0St_UX))))
+        !(env->CP0_Status & (1 << CP0St_UX)))
         env->hflags &= ~MIPS_HFLAG_64;
 #endif
     if (loglevel & CPU_LOG_EXEC)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index ddffc0f..004b2f7 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -142,7 +142,7 @@
     OPC_SRL      = 0x02 | OPC_SPECIAL, /* also ROTR */
     OPC_SRA      = 0x03 | OPC_SPECIAL,
     OPC_SLLV     = 0x04 | OPC_SPECIAL,
-    OPC_SRLV     = 0x06 | OPC_SPECIAL,
+    OPC_SRLV     = 0x06 | OPC_SPECIAL, /* also ROTRV */
     OPC_SRAV     = 0x07 | OPC_SPECIAL,
     OPC_DSLLV    = 0x14 | OPC_SPECIAL,
     OPC_DSRLV    = 0x16 | OPC_SPECIAL, /* also DROTRV */
@@ -761,10 +761,10 @@
 }
 
 /* This code generates a "reserved instruction" exception if the
-   CPU is not a MIPS R2 (or higher) CPU. */
-static inline void check_mips_r2(CPUState *env, DisasContext *ctx)
+   CPU does not support the instruction set corresponding to flags. */
+static inline void check_insn(CPUState *env, DisasContext *ctx, int flags)
 {
-    if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) < (1 << CP0C0_AR))
+    if (unlikely(!(env->insn_flags & flags)))
         generate_exception(ctx, EXCP_RI);
 }
 
@@ -776,6 +776,14 @@
         generate_exception(ctx, EXCP_RI);
 }
 
+/* This code generates a "reserved instruction" exception if 64-bit
+   instructions are not enabled. */
+static inline void check_mips_64(DisasContext *ctx)
+{
+    if (!(ctx->hflags & MIPS_HFLAG_64))
+        generate_exception(ctx, EXCP_RI);
+}
+
 #if defined(CONFIG_USER_ONLY)
 #define op_ldst(name)        gen_op_##name##_raw()
 #define OP_LD_TABLE(width)
@@ -1024,8 +1032,8 @@
 }
 
 /* Arithmetic with immediate operand */
-static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
-                           int rs, int16_t imm)
+static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc,
+                           int rt, int rs, int16_t imm)
 {
     target_ulong uimm;
     const char *opn = "imm arith";
@@ -1132,8 +1140,14 @@
             opn = "srl";
             break;
         case 1:
-            gen_op_rotr();
-            opn = "rotr";
+            /* rotr is decoded as srl on non-R2 CPUs */
+            if (env->insn_flags & ISA_MIPS32R2) {
+                gen_op_rotr();
+                opn = "rotr";
+            } else {
+                gen_op_srl();
+                opn = "srl";
+            }
             break;
         default:
             MIPS_INVAL("invalid srl flag");
@@ -1157,8 +1171,14 @@
             opn = "dsrl";
             break;
         case 1:
-            gen_op_drotr();
-            opn = "drotr";
+            /* drotr is decoded as dsrl on non-R2 CPUs */
+            if (env->insn_flags & ISA_MIPS32R2) {
+                gen_op_drotr();
+                opn = "drotr";
+            } else {
+                gen_op_dsrl();
+                opn = "dsrl";
+            }
             break;
         default:
             MIPS_INVAL("invalid dsrl flag");
@@ -1181,8 +1201,14 @@
             opn = "dsrl32";
             break;
         case 1:
-            gen_op_drotr32();
-            opn = "drotr32";
+            /* drotr32 is decoded as dsrl32 on non-R2 CPUs */
+            if (env->insn_flags & ISA_MIPS32R2) {
+                gen_op_drotr32();
+                opn = "drotr32";
+            } else {
+                gen_op_dsrl32();
+                opn = "dsrl32";
+            }
             break;
         default:
             MIPS_INVAL("invalid dsrl32 flag");
@@ -1201,7 +1227,7 @@
 }
 
 /* Arithmetic */
-static void gen_arith (DisasContext *ctx, uint32_t opc,
+static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
                        int rd, int rs, int rt)
 {
     const char *opn = "arith";
@@ -1305,8 +1331,14 @@
             opn = "srlv";
             break;
         case 1:
-            gen_op_rotrv();
-            opn = "rotrv";
+            /* rotrv is decoded as srlv on non-R2 CPUs */
+            if (env->insn_flags & ISA_MIPS32R2) {
+                gen_op_rotrv();
+                opn = "rotrv";
+            } else {
+                gen_op_srlv();
+                opn = "srlv";
+            }
             break;
         default:
             MIPS_INVAL("invalid srlv flag");
@@ -1330,8 +1362,14 @@
             opn = "dsrlv";
             break;
         case 1:
-            gen_op_drotrv();
-            opn = "drotrv";
+            /* drotrv is decoded as dsrlv on non-R2 CPUs */
+            if (env->insn_flags & ISA_MIPS32R2) {
+                gen_op_drotrv();
+                opn = "drotrv";
+            } else {
+                gen_op_dsrlv();
+                opn = "dsrlv";
+            }
             break;
         default:
             MIPS_INVAL("invalid dsrlv flag");
@@ -1910,6 +1948,9 @@
 {
     const char *rn = "invalid";
 
+    if (sel != 0)
+        check_insn(env, ctx, ISA_MIPS32);
+
     switch (reg) {
     case 0:
         switch (sel) {
@@ -2057,7 +2098,7 @@
             rn = "PageMask";
             break;
         case 1:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_pagegrain();
             rn = "PageGrain";
             break;
@@ -2072,22 +2113,27 @@
             rn = "Wired";
             break;
         case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsconf0();
             rn = "SRSConf0";
             break;
         case 2:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsconf1();
             rn = "SRSConf1";
             break;
         case 3:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsconf2();
             rn = "SRSConf2";
             break;
         case 4:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsconf3();
             rn = "SRSConf3";
             break;
         case 5:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsconf4();
             rn = "SRSConf4";
             break;
@@ -2098,7 +2144,7 @@
     case 7:
         switch (sel) {
         case 0:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_hwrena();
             rn = "HWREna";
             break;
@@ -2155,17 +2201,17 @@
             rn = "Status";
             break;
         case 1:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_intctl();
             rn = "IntCtl";
             break;
         case 2:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsctl();
             rn = "SRSCtl";
             break;
         case 3:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsmap();
             rn = "SRSMap";
             break;
@@ -2200,7 +2246,7 @@
             rn = "PRid";
             break;
         case 1:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_ebase();
             rn = "EBase";
             break;
@@ -2274,8 +2320,7 @@
         switch (sel) {
         case 0:
 #ifdef TARGET_MIPS64
-	    if (!(ctx->hflags & MIPS_HFLAG_64))
-	        goto die;
+            check_insn(env, ctx, ISA_MIPS3);
             gen_op_mfc0_xcontext();
             rn = "XContext";
             break;
@@ -2471,6 +2516,9 @@
 {
     const char *rn = "invalid";
 
+    if (sel != 0)
+        check_insn(env, ctx, ISA_MIPS32);
+
     switch (reg) {
     case 0:
         switch (sel) {
@@ -2618,7 +2666,7 @@
             rn = "PageMask";
             break;
         case 1:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_pagegrain();
             rn = "PageGrain";
             break;
@@ -2633,22 +2681,27 @@
             rn = "Wired";
             break;
         case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsconf0();
             rn = "SRSConf0";
             break;
         case 2:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsconf1();
             rn = "SRSConf1";
             break;
         case 3:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsconf2();
             rn = "SRSConf2";
             break;
         case 4:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsconf3();
             rn = "SRSConf3";
             break;
         case 5:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsconf4();
             rn = "SRSConf4";
             break;
@@ -2659,7 +2712,7 @@
     case 7:
         switch (sel) {
         case 0:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_hwrena();
             rn = "HWREna";
             break;
@@ -2717,21 +2770,21 @@
             rn = "Status";
             break;
         case 1:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_intctl();
             /* Stop translation as we may have switched the execution mode */
             ctx->bstate = BS_STOP;
             rn = "IntCtl";
             break;
         case 2:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsctl();
             /* Stop translation as we may have switched the execution mode */
             ctx->bstate = BS_STOP;
             rn = "SRSCtl";
             break;
         case 3:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsmap();
             /* Stop translation as we may have switched the execution mode */
             ctx->bstate = BS_STOP;
@@ -2770,7 +2823,7 @@
             rn = "PRid";
             break;
         case 1:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_ebase();
             rn = "EBase";
             break;
@@ -2849,8 +2902,7 @@
         switch (sel) {
         case 0:
 #ifdef TARGET_MIPS64
-	    if (!(ctx->hflags & MIPS_HFLAG_64))
-	        goto die;
+            check_insn(env, ctx, ISA_MIPS3);
             gen_op_mtc0_xcontext();
             rn = "XContext";
             break;
@@ -3064,6 +3116,9 @@
 {
     const char *rn = "invalid";
 
+    if (sel != 0)
+        check_insn(env, ctx, ISA_MIPS64);
+
     switch (reg) {
     case 0:
         switch (sel) {
@@ -3211,7 +3266,7 @@
             rn = "PageMask";
             break;
         case 1:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_pagegrain();
             rn = "PageGrain";
             break;
@@ -3226,22 +3281,27 @@
             rn = "Wired";
             break;
         case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsconf0();
             rn = "SRSConf0";
             break;
         case 2:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsconf1();
             rn = "SRSConf1";
             break;
         case 3:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsconf2();
             rn = "SRSConf2";
             break;
         case 4:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsconf3();
             rn = "SRSConf3";
             break;
         case 5:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsconf4();
             rn = "SRSConf4";
             break;
@@ -3252,7 +3312,7 @@
     case 7:
         switch (sel) {
         case 0:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_hwrena();
             rn = "HWREna";
             break;
@@ -3309,17 +3369,17 @@
             rn = "Status";
             break;
         case 1:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_intctl();
             rn = "IntCtl";
             break;
         case 2:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsctl();
             rn = "SRSCtl";
             break;
         case 3:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_srsmap();
             rn = "SRSMap";
             break;
@@ -3354,7 +3414,7 @@
             rn = "PRid";
             break;
         case 1:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mfc0_ebase();
             rn = "EBase";
             break;
@@ -3418,6 +3478,7 @@
     case 20:
         switch (sel) {
         case 0:
+            check_insn(env, ctx, ISA_MIPS3);
             gen_op_dmfc0_xcontext();
             rn = "XContext";
             break;
@@ -3612,6 +3673,9 @@
 {
     const char *rn = "invalid";
 
+    if (sel != 0)
+        check_insn(env, ctx, ISA_MIPS64);
+
     switch (reg) {
     case 0:
         switch (sel) {
@@ -3759,7 +3823,7 @@
             rn = "PageMask";
             break;
         case 1:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_pagegrain();
             rn = "PageGrain";
             break;
@@ -3774,22 +3838,27 @@
             rn = "Wired";
             break;
         case 1:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsconf0();
             rn = "SRSConf0";
             break;
         case 2:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsconf1();
             rn = "SRSConf1";
             break;
         case 3:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsconf2();
             rn = "SRSConf2";
             break;
         case 4:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsconf3();
             rn = "SRSConf3";
             break;
         case 5:
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsconf4();
             rn = "SRSConf4";
             break;
@@ -3800,7 +3869,7 @@
     case 7:
         switch (sel) {
         case 0:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_hwrena();
             rn = "HWREna";
             break;
@@ -3858,21 +3927,21 @@
             rn = "Status";
             break;
         case 1:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_intctl();
             /* Stop translation as we may have switched the execution mode */
             ctx->bstate = BS_STOP;
             rn = "IntCtl";
             break;
         case 2:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsctl();
             /* Stop translation as we may have switched the execution mode */
             ctx->bstate = BS_STOP;
             rn = "SRSCtl";
             break;
         case 3:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_srsmap();
             /* Stop translation as we may have switched the execution mode */
             ctx->bstate = BS_STOP;
@@ -3911,7 +3980,7 @@
             rn = "PRid";
             break;
         case 1:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             gen_op_mtc0_ebase();
             rn = "EBase";
             break;
@@ -3980,6 +4049,7 @@
     case 20:
         switch (sel) {
         case 0:
+            check_insn(env, ctx, ISA_MIPS3);
             gen_op_mtc0_xcontext();
             rn = "XContext";
             break;
@@ -4535,8 +4605,7 @@
         break;
 #ifdef TARGET_MIPS64
     case OPC_DMFC0:
-        if (!(ctx->hflags & MIPS_HFLAG_64))
-            generate_exception(ctx, EXCP_RI);
+        check_insn(env, ctx, ISA_MIPS3);
         if (rt == 0) {
             /* Treat as NOP. */
             return;
@@ -4546,8 +4615,7 @@
         opn = "dmfc0";
         break;
     case OPC_DMTC0:
-        if (!(ctx->hflags & MIPS_HFLAG_64))
-            generate_exception(ctx, EXCP_RI);
+        check_insn(env, ctx, ISA_MIPS3);
         GEN_LOAD_REG_TN(T0, rt);
         gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7);
         opn = "dmtc0";
@@ -4597,11 +4665,13 @@
         break;
     case OPC_ERET:
         opn = "eret";
+        check_insn(env, ctx, ISA_MIPS2);
         gen_op_eret();
         ctx->bstate = BS_EXCP;
         break;
     case OPC_DERET:
         opn = "deret";
+        check_insn(env, ctx, ISA_MIPS32);
         if (!(ctx->hflags & MIPS_HFLAG_DM)) {
             MIPS_INVAL(opn);
             generate_exception(ctx, EXCP_RI);
@@ -4612,6 +4682,7 @@
         break;
     case OPC_WAIT:
         opn = "wait";
+        check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32);
         /* If we get an exception, we want to restart at next instruction */
         ctx->pc += 4;
         save_cpu_state(ctx, 1);
@@ -4629,12 +4700,15 @@
 }
 
 /* CP1 Branches (before delay slot) */
-static void gen_compute_branch1 (DisasContext *ctx, uint32_t op,
+static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op,
                                  int32_t cc, int32_t offset)
 {
     target_ulong btarget;
     const char *opn = "cp1 cond branch";
 
+    if (cc != 0)
+        check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
+
     btarget = ctx->pc + 4 + offset;
 
     switch (op) {
@@ -5843,14 +5917,15 @@
         switch (op1) {
         case OPC_SLL:          /* Arithmetic with immediate */
         case OPC_SRL ... OPC_SRA:
-            gen_arith_imm(ctx, op1, rd, rt, sa);
+            gen_arith_imm(env, ctx, op1, rd, rt, sa);
             break;
+        case OPC_MOVZ ... OPC_MOVN:
+            check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
         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);
+            gen_arith(env, ctx, op1, rd, rs, rt);
             break;
         case OPC_MULT ... OPC_DIVU:
             gen_muldiv(ctx, op1, rs, rt);
@@ -5899,6 +5974,7 @@
             break;
 
         case OPC_MOVCI:
+            check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
             if (env->CP0_Config1 & (1 << CP0C1_FP)) {
                 save_cpu_state(ctx, 1);
                 check_cp1_enabled(ctx);
@@ -5915,20 +5991,20 @@
         case OPC_DSRL ... OPC_DSRA:
         case OPC_DSLL32:
         case OPC_DSRL32 ... OPC_DSRA32:
-            if (!(ctx->hflags & MIPS_HFLAG_64))
-                generate_exception(ctx, EXCP_RI);
-            gen_arith_imm(ctx, op1, rd, rt, sa);
+            check_insn(env, ctx, ISA_MIPS3);
+            check_mips_64(ctx);
+            gen_arith_imm(env, ctx, op1, rd, rt, sa);
             break;
         case OPC_DSLLV:
         case OPC_DSRLV ... OPC_DSRAV:
         case OPC_DADD ... OPC_DSUBU:
-            if (!(ctx->hflags & MIPS_HFLAG_64))
-                generate_exception(ctx, EXCP_RI);
-            gen_arith(ctx, op1, rd, rs, rt);
+            check_insn(env, ctx, ISA_MIPS3);
+            check_mips_64(ctx);
+            gen_arith(env, ctx, op1, rd, rs, rt);
             break;
         case OPC_DMULT ... OPC_DDIVU:
-            if (!(ctx->hflags & MIPS_HFLAG_64))
-                generate_exception(ctx, EXCP_RI);
+            check_insn(env, ctx, ISA_MIPS3);
+            check_mips_64(ctx);
             gen_muldiv(ctx, op1, rs, rt);
             break;
 #endif
@@ -5943,18 +6019,21 @@
         switch (op1) {
         case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
         case OPC_MSUB ... OPC_MSUBU:
+            check_insn(env, ctx, ISA_MIPS32);
             gen_muldiv(ctx, op1, rs, rt);
             break;
         case OPC_MUL:
-            gen_arith(ctx, op1, rd, rs, rt);
+            gen_arith(env, ctx, op1, rd, rs, rt);
             break;
         case OPC_CLZ ... OPC_CLO:
+            check_insn(env, ctx, ISA_MIPS32);
             gen_cl(ctx, op1, rd, rs);
             break;
         case OPC_SDBBP:
             /* XXX: not clear which exception should be raised
              *      when in debug mode...
              */
+            check_insn(env, ctx, ISA_MIPS32);
             if (!(ctx->hflags & MIPS_HFLAG_DM)) {
                 generate_exception(ctx, EXCP_DBp);
             } else {
@@ -5964,8 +6043,8 @@
             break;
 #ifdef TARGET_MIPS64
         case OPC_DCLZ ... OPC_DCLO:
-            if (!(ctx->hflags & MIPS_HFLAG_64))
-                generate_exception(ctx, EXCP_RI);
+            check_insn(env, ctx, ISA_MIPS64);
+            check_mips_64(ctx);
             gen_cl(ctx, op1, rd, rs);
             break;
 #endif
@@ -5976,14 +6055,15 @@
         }
         break;
     case OPC_SPECIAL3:
-         check_mips_r2(env, ctx);
          op1 = MASK_SPECIAL3(ctx->opcode);
          switch (op1) {
          case OPC_EXT:
          case OPC_INS:
+             check_insn(env, ctx, ISA_MIPS32R2);
              gen_bitops(ctx, op1, rt, rs, sa, rd);
              break;
          case OPC_BSHFL:
+             check_insn(env, ctx, ISA_MIPS32R2);
              op2 = MASK_BSHFL(ctx->opcode);
              switch (op2) {
              case OPC_WSBH:
@@ -6006,6 +6086,7 @@
             GEN_STORE_TN_REG(rd, T0);
             break;
         case OPC_RDHWR:
+            check_insn(env, ctx, ISA_MIPS32R2);
             switch (rd) {
             case 0:
                 save_cpu_state(ctx, 1);
@@ -6050,13 +6131,13 @@
 #ifdef TARGET_MIPS64
         case OPC_DEXTM ... OPC_DEXT:
         case OPC_DINSM ... OPC_DINS:
-            if (!(ctx->hflags & MIPS_HFLAG_64))
-                generate_exception(ctx, EXCP_RI);
+            check_insn(env, ctx, ISA_MIPS64R2);
+            check_mips_64(ctx);
             gen_bitops(ctx, op1, rt, rs, sa, rd);
             break;
         case OPC_DBSHFL:
-            if (!(ctx->hflags & MIPS_HFLAG_64))
-                generate_exception(ctx, EXCP_RI);
+            check_insn(env, ctx, ISA_MIPS64R2);
+            check_mips_64(ctx);
             op2 = MASK_DBSHFL(ctx->opcode);
             switch (op2) {
             case OPC_DSBH:
@@ -6092,7 +6173,7 @@
             gen_trap(ctx, op1, rs, -1, imm);
             break;
         case OPC_SYNCI:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             /* Treat as NOP. */
             break;
         default:            /* Invalid */
@@ -6120,7 +6201,6 @@
             gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd);
             break;
         case OPC_MFMC0:
-            check_mips_r2(env, ctx);
             op2 = MASK_MFMC0(ctx->opcode);
             switch (op2) {
             case OPC_DMT:
@@ -6140,11 +6220,13 @@
                 gen_op_evpe();
                 break;
             case OPC_DI:
+                check_insn(env, ctx, ISA_MIPS32R2);
                 gen_op_di();
                 /* Stop translation as we may have switched the execution mode */
                 ctx->bstate = BS_STOP;
                 break;
             case OPC_EI:
+                check_insn(env, ctx, ISA_MIPS32R2);
                 gen_op_ei();
                 /* Stop translation as we may have switched the execution mode */
                 ctx->bstate = BS_STOP;
@@ -6157,12 +6239,12 @@
             GEN_STORE_TN_REG(rt, T0);
             break;
         case OPC_RDPGPR:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             GEN_LOAD_SRSREG_TN(T0, rt);
             GEN_STORE_TN_REG(rd, T0);
             break;
         case OPC_WRPGPR:
-            check_mips_r2(env, ctx);
+            check_insn(env, ctx, ISA_MIPS32R2);
             GEN_LOAD_REG_TN(T0, rt);
             GEN_STORE_TN_SRSREG(rd, T0);
             break;
@@ -6173,7 +6255,7 @@
         }
         break;
     case OPC_ADDI ... OPC_LUI: /* Arithmetic with immediate opcode */
-         gen_arith_imm(ctx, op, rt, rs, imm);
+         gen_arith_imm(env, ctx, op, rt, rs, imm);
          break;
     case OPC_J ... OPC_JAL: /* Jump */
          offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
@@ -6191,9 +6273,11 @@
          gen_ldst(ctx, op, rt, rs, imm);
          break;
     case OPC_CACHE:
+        check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32);
         /* Treat as NOP. */
         break;
     case OPC_PREF:
+        check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
         /* Treat as NOP. */
         break;
 
@@ -6219,21 +6303,24 @@
             switch (op1) {
             case OPC_MFHC1:
             case OPC_MTHC1:
-                check_mips_r2(env, ctx);
+                check_insn(env, ctx, ISA_MIPS32R2);
             case OPC_MFC1:
             case OPC_CFC1:
             case OPC_MTC1:
             case OPC_CTC1:
+                gen_cp1(ctx, op1, rt, rd);
+                break;
 #ifdef TARGET_MIPS64
             case OPC_DMFC1:
             case OPC_DMTC1:
-#endif
+                check_insn(env, ctx, ISA_MIPS3);
                 gen_cp1(ctx, op1, rt, rd);
                 break;
+#endif
             case OPC_BC1:
             case OPC_BC1ANY2:
             case OPC_BC1ANY4:
-                gen_compute_branch1(ctx, MASK_BC1(ctx->opcode),
+                gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode),
                                     (rt >> 2) & 0x7, imm << 2);
                 return;
             case OPC_S_FMT:
@@ -6315,24 +6402,22 @@
     case OPC_LD:
     case OPC_SCD:
     case OPC_SD:
-        if (!(ctx->hflags & MIPS_HFLAG_64))
-            generate_exception(ctx, EXCP_RI);
+        check_insn(env, ctx, ISA_MIPS3);
+        check_mips_64(ctx);
         gen_ldst(ctx, op, rt, rs, imm);
         break;
     case OPC_DADDI ... OPC_DADDIU:
-        if (!(ctx->hflags & MIPS_HFLAG_64))
-            generate_exception(ctx, EXCP_RI);
-        gen_arith_imm(ctx, op, rt, rs, imm);
+        check_insn(env, ctx, ISA_MIPS3);
+        check_mips_64(ctx);
+        gen_arith_imm(env, ctx, op, rt, rs, imm);
         break;
 #endif
-#ifdef MIPS_HAS_MIPS16
     case OPC_JALX:
+        check_insn(env, ctx, ASE_MIPS16);
         /* MIPS16: Not implemented. */
-#endif
-#ifdef MIPS_HAS_MDMX
     case OPC_MDMX:
+        check_insn(env, ctx, ASE_MDMX);
         /* MDMX: Not implemented. */
-#endif
     default:            /* Invalid */
         MIPS_INVAL("major opcode");
         generate_exception(ctx, EXCP_RI);
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index 1a98973..6bea0c4 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -80,6 +80,7 @@
     int32_t CP0_SRSConf3;
     int32_t CP0_SRSConf4_rw_bitmask;
     int32_t CP0_SRSConf4;
+    int insn_flags;
 };
 
 /*****************************************************************************/
@@ -98,6 +99,7 @@
         .SYNCI_Step = 32,
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x1278FF17,
+        .insn_flags = CPU_MIPS32 | ASE_MIPS16,
     },
     {
         .name = "4KEcR1",
@@ -111,6 +113,7 @@
         .SYNCI_Step = 32,
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x1278FF17,
+        .insn_flags = CPU_MIPS32 | ASE_MIPS16,
     },
     {
         .name = "4KEc",
@@ -124,6 +127,7 @@
         .SYNCI_Step = 32,
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x1278FF17,
+        .insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
     },
     {
         .name = "24Kc",
@@ -138,6 +142,7 @@
         .CCRes = 2,
         /* No DSP implemented. */
         .CP0_Status_rw_bitmask = 0x1278FF17,
+        .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP,
     },
     {
         .name = "24Kf",
@@ -154,6 +159,7 @@
         .CP0_Status_rw_bitmask = 0x3678FF17,
         .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
                     (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
+        .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP,
     },
     {
         .name = "34Kf",
@@ -193,6 +199,7 @@
         .CP0_SRSConf4_rw_bitmask = 0x3fffffff,
         .CP0_SRSConf4 = (0x3fe << CP0SRSC4_SRS15) |
                     (0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13),
+        .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP,
     },
 #ifdef TARGET_MIPS64
     {
@@ -210,6 +217,7 @@
 	/* The R4000 has a full 64bit FPU doesn't use the fcr0 bits. */
         .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV),
         .SEGBITS = 40,
+        .insn_flags = CPU_MIPS3,
     },
     {
         .name = "5Kc",
@@ -225,6 +233,7 @@
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x32F8FFFF,
         .SEGBITS = 42,
+        .insn_flags = CPU_MIPS64,
     },
     {
         .name = "5Kf",
@@ -243,6 +252,7 @@
         .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) |
                     (0x81 << FCR0_PRID) | (0x0 << FCR0_REV),
         .SEGBITS = 42,
+        .insn_flags = CPU_MIPS64,
     },
     {
         .name = "20Kc",
@@ -264,6 +274,7 @@
                     (1 << FCR0_D) | (1 << FCR0_S) |
                     (0x82 << FCR0_PRID) | (0x0 << FCR0_REV),
         .SEGBITS = 40,
+        .insn_flags = CPU_MIPS64 | ASE_MIPS3D,
     },
 #endif
 };
@@ -406,7 +417,7 @@
     env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask;
     env->CP0_SRSCtl = def->CP0_SRSCtl;
 #ifdef TARGET_MIPS64
-    if ((env->CP0_Config0 & (0x3 << CP0C0_AT)))
+    if (def->insn_flags & ISA_MIPS3)
     {
         env->hflags |= MIPS_HFLAG_64;
         env->SEGBITS = def->SEGBITS;
@@ -426,6 +437,7 @@
     env->CP0_SRSConf3 = def->CP0_SRSConf3;
     env->CP0_SRSConf4_rw_bitmask = def->CP0_SRSConf4_rw_bitmask;
     env->CP0_SRSConf4 = def->CP0_SRSConf4;
+    env->insn_flags = def->insn_flags;
 
 #ifndef CONFIG_USER_ONLY
     mmu_init(env, def);