Handle PX/UX status flags correctly, by Aurelien Jarno.
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Mon, 28 May 2007 20:36:48 +0000 (20:36 +0000)
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Mon, 28 May 2007 20:36:48 +0000 (20:36 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2892 c046a42c-6fe2-441c-8c8c-71466251a162

target-mips/cpu.h
target-mips/helper.c
target-mips/op.c
target-mips/translate.c

index 9cddc17..17ac4ac 100644 (file)
@@ -260,6 +260,7 @@ struct CPUMIPSState {
 #define MIPS_HFLAG_UM     0x0001 /* user mode                          */
 #define MIPS_HFLAG_DM     0x0008 /* Debug mode                         */
 #define MIPS_HFLAG_SM     0x0010 /* Supervisor mode                    */
+#define MIPS_HFLAG_64     0x0020 /* 64-bit instructions enabled        */
 #define MIPS_HFLAG_RE     0x0040 /* Reversed endianness                */
     /* If translation is interrupted between the branch instruction and
      * the delay slot, record what type of branch it is so that we can
index 2dfaffc..9da6212 100644 (file)
@@ -370,6 +370,7 @@ void do_interrupt (CPUState *env)
         }
     enter_debug_mode:
         env->hflags |= MIPS_HFLAG_DM;
+        env->hflags |= MIPS_HFLAG_64;
         env->hflags &= ~MIPS_HFLAG_UM;
         /* EJTAG probe trap enable is not implemented... */
         if (!(env->CP0_Status & (1 << CP0St_EXL)))
@@ -395,6 +396,7 @@ void do_interrupt (CPUState *env)
             env->CP0_ErrorEPC = env->PC;
         }
         env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
+        env->hflags |= MIPS_HFLAG_64;
         env->hflags &= ~MIPS_HFLAG_UM;
         if (!(env->CP0_Status & (1 << CP0St_EXL)))
             env->CP0_Cause &= ~(1 << CP0Ca_BD);
@@ -493,6 +495,7 @@ void do_interrupt (CPUState *env)
                 env->CP0_Cause &= ~(1 << CP0Ca_BD);
             }
             env->CP0_Status |= (1 << CP0St_EXL);
+            env->hflags |= MIPS_HFLAG_64;
             env->hflags &= ~MIPS_HFLAG_UM;
         }
         env->hflags &= ~MIPS_HFLAG_BMASK;
index f4598fb..bc4d51a 100644 (file)
@@ -1358,6 +1358,12 @@ void op_mtc0_status (void)
         !(env->hflags & MIPS_HFLAG_DM) &&
         (val & (1 << CP0St_UM)))
         env->hflags |= MIPS_HFLAG_UM;
+#ifdef TARGET_MIPS64
+    if ((env->hflags & MIPS_HFLAG_UM) &&
+        !(val & (1 << CP0St_PX)) &&
+        !(val & (1 << CP0St_UX)))
+        env->hflags &= ~MIPS_HFLAG_64;
+#endif
     env->CP0_Status = (env->CP0_Status & ~mask) | val;
     if (loglevel & CPU_LOG_EXEC)
         CALL_FROM_TB2(do_mtc0_status_debug, old, val);
@@ -2338,6 +2344,12 @@ void op_eret (void)
         !(env->hflags & MIPS_HFLAG_DM) &&
         (env->CP0_Status & (1 << CP0St_UM)))
         env->hflags |= MIPS_HFLAG_UM;
+#ifdef TARGET_MIPS64
+    if ((env->hflags & MIPS_HFLAG_UM) &&
+        !(env->CP0_Status & (1 << CP0St_PX)) &&
+        !(env->CP0_Status & (1 << CP0St_UX)))
+        env->hflags &= ~MIPS_HFLAG_64;
+#endif
     if (loglevel & CPU_LOG_EXEC)
         CALL_FROM_TB0(debug_post_eret);
     env->CP0_LLAddr = 1;
@@ -2355,6 +2367,12 @@ void op_deret (void)
         !(env->hflags & MIPS_HFLAG_DM) &&
         (env->CP0_Status & (1 << CP0St_UM)))
         env->hflags |= MIPS_HFLAG_UM;
+#ifdef TARGET_MIPS64
+    if ((env->hflags & MIPS_HFLAG_UM) &&
+        !(env->CP0_Status & (1 << CP0St_PX)) &&
+        !(env->CP0_Status & (1 << CP0St_UX)))
+        env->hflags &= ~MIPS_HFLAG_64;
+#endif
     if (loglevel & CPU_LOG_EXEC)
         CALL_FROM_TB0(debug_post_eret);
     env->CP0_LLAddr = 1;
index ffa5c4b..c0f2b81 100644 (file)
@@ -730,9 +730,9 @@ OP_ST_TABLE(dl);
 OP_ST_TABLE(dr);
 OP_LD_TABLE(ld);
 OP_ST_TABLE(cd);
+OP_LD_TABLE(wu);
 #endif
 OP_LD_TABLE(w);
-OP_LD_TABLE(wu);
 OP_LD_TABLE(wl);
 OP_LD_TABLE(wr);
 OP_ST_TABLE(w);
@@ -773,6 +773,11 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
      */
     switch (opc) {
 #ifdef TARGET_MIPS64
+    case OPC_LWU:
+        op_ldst(lwu);
+        GEN_STORE_TN_REG(rt, T0);
+        opn = "lwu";
+        break;
     case OPC_LD:
         op_ldst(ld);
         GEN_STORE_TN_REG(rt, T0);
@@ -823,11 +828,6 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
         GEN_STORE_TN_REG(rt, T0);
         opn = "lw";
         break;
-    case OPC_LWU:
-        op_ldst(lwu);
-        GEN_STORE_TN_REG(rt, T0);
-        opn = "lwu";
-        break;
     case OPC_SW:
         GEN_LOAD_REG_TN(T1, rt);
         op_ldst(sw);
@@ -5377,14 +5377,20 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
         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);
             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);
             break;
         case OPC_DMULT ... OPC_DDIVU:
+            if (!(ctx->hflags & MIPS_HFLAG_64))
+                generate_exception(ctx, EXCP_RI);
             gen_muldiv(ctx, op1, rs, rt);
             break;
 #endif
@@ -5420,6 +5426,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
             break;
 #ifdef TARGET_MIPS64
         case OPC_DCLZ ... OPC_DCLO:
+            if (!(ctx->hflags & MIPS_HFLAG_64))
+                generate_exception(ctx, EXCP_RI);
             gen_cl(ctx, op1, rd, rs);
             break;
 #endif
@@ -5491,9 +5499,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
 #ifdef TARGET_MIPS64
         case OPC_DEXTM ... OPC_DEXT:
         case OPC_DINSM ... OPC_DINS:
+            if (!(ctx->hflags & MIPS_HFLAG_64))
+                generate_exception(ctx, EXCP_RI);
             gen_bitops(ctx, op1, rt, rs, sa, rd);
             break;
         case OPC_DBSHFL:
+            if (!(ctx->hflags & MIPS_HFLAG_64))
+                generate_exception(ctx, EXCP_RI);
             op2 = MASK_DBSHFL(ctx->opcode);
             switch (op2) {
             case OPC_DSBH:
@@ -5732,9 +5744,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
     case OPC_LD:
     case OPC_SCD:
     case OPC_SD:
+        if (!(ctx->hflags & MIPS_HFLAG_64))
+            generate_exception(ctx, EXCP_RI);
         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);
         break;
 #endif
@@ -6072,11 +6088,14 @@ void cpu_reset (CPUMIPSState *env)
         /* If the exception was raised from a delay slot,
          * come back to the jump.  */
         env->CP0_ErrorEPC = env->PC - 4;
-        env->hflags &= ~MIPS_HFLAG_BMASK;
     } else {
         env->CP0_ErrorEPC = env->PC;
     }
+#ifdef TARGET_MIPS64
+    env->hflags = MIPS_HFLAG_64;
+#else
     env->hflags = 0;
+#endif
     env->PC = (int32_t)0xBFC00000;
     env->CP0_Wired = 0;
     /* SMP not implemented */