]> Git Repo - qemu.git/blobdiff - target-mips/translate.c
Fix exception handling cornercase for rdhwr.
[qemu.git] / target-mips / translate.c
index 816b91e1c59cc361d18652b544af09f8aaac45d7..57527a5e960295a8f4a99f24049e64ac5fd788bb 100644 (file)
@@ -358,7 +358,44 @@ enum {
 #define MASK_CP1_FUNC(op)       MASK_CP1(op) | (op & 0x3F)
 
 #define MASK_CP2(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
-#define MASK_CP3(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+
+enum {
+    OPC_MFC2    = (0x00 << 21) | OPC_CP2,
+    OPC_DMFC2   = (0x01 << 21) | OPC_CP2,
+    OPC_CFC2    = (0x02 << 21) | OPC_CP2,
+    OPC_MFHC2   = (0x03 << 21) | OPC_CP2,
+    OPC_MTC2    = (0x04 << 21) | OPC_CP2,
+    OPC_DMTC2   = (0x05 << 21) | OPC_CP2,
+    OPC_CTC2    = (0x06 << 21) | OPC_CP2,
+    OPC_MTHC2   = (0x07 << 21) | OPC_CP2,
+    OPC_BC2     = (0x08 << 21) | OPC_CP2,
+};
+
+#define MASK_CP3(op)       MASK_OP_MAJOR(op) | (op & 0x3F)
+
+enum {
+    OPC_LWXC1   = 0x00 | OPC_CP3,
+    OPC_LDXC1   = 0x01 | OPC_CP3,
+    OPC_LUXC1   = 0x05 | OPC_CP3,
+    OPC_SWXC1   = 0x08 | OPC_CP3,
+    OPC_SDXC1   = 0x09 | OPC_CP3,
+    OPC_SUXC1   = 0x0D | OPC_CP3,
+    OPC_PREFX   = 0x0F | OPC_CP3,
+    OPC_ALNV_PS = 0x1E | OPC_CP3,
+    OPC_MADD_S  = 0x20 | OPC_CP3,
+    OPC_MADD_D  = 0x21 | OPC_CP3,
+    OPC_MADD_PS = 0x26 | OPC_CP3,
+    OPC_MSUB_S  = 0x28 | OPC_CP3,
+    OPC_MSUB_D  = 0x29 | OPC_CP3,
+    OPC_MSUB_PS = 0x2E | OPC_CP3,
+    OPC_NMADD_S = 0x30 | OPC_CP3,
+    OPC_NMADD_D = 0x32 | OPC_CP3,
+    OPC_NMADD_PS= 0x36 | OPC_CP3,
+    OPC_NMSUB_S = 0x38 | OPC_CP3,
+    OPC_NMSUB_D = 0x39 | OPC_CP3,
+    OPC_NMSUB_PS= 0x3E | OPC_CP3,
+};
+
 
 const unsigned char *regnames[] =
     { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
@@ -849,18 +886,43 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
         MIPS_DEBUG("NOP");
         return;
     }
-    if (opc == OPC_ADDI || opc == OPC_ADDIU ||
-        opc == OPC_DADDI || opc == OPC_DADDIU ||
-        opc == OPC_SLTI || opc == OPC_SLTIU)
+    uimm = (uint16_t)imm;
+    switch (opc) {
+    case OPC_ADDI:
+    case OPC_ADDIU:
+#ifdef TARGET_MIPS64
+    case OPC_DADDI:
+    case OPC_DADDIU:
+#endif
+    case OPC_SLTI:
+    case OPC_SLTIU:
         uimm = (int32_t)imm; /* Sign extend to 32 bits */
-    else
-        uimm = (uint16_t)imm;
-    if (opc != OPC_LUI) {
+        /* Fall through. */
+    case OPC_ANDI:
+    case OPC_ORI:
+    case OPC_XORI:
         GEN_LOAD_REG_TN(T0, rs);
         GEN_LOAD_IMM_TN(T1, uimm);
-    } else {
-        uimm = uimm << 16;
+        break;
+    case OPC_LUI:
+        uimm <<= 16;
         GEN_LOAD_IMM_TN(T0, uimm);
+        break;
+    case OPC_SLL:
+    case OPC_SRA:
+    case OPC_SRL:
+#ifdef TARGET_MIPS64
+    case OPC_DSLL:
+    case OPC_DSRA:
+    case OPC_DSRL:
+    case OPC_DSLL32:
+    case OPC_DSRA32:
+    case OPC_DSRL32:
+#endif
+        uimm &= 0x1f;
+        GEN_LOAD_REG_TN(T0, rs);
+        GEN_LOAD_IMM_TN(T1, uimm);
+        break;
     }
     switch (opc) {
     case OPC_ADDI:
@@ -915,13 +977,20 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
         opn = "sra";
         break;
     case OPC_SRL:
-       if ((ctx->opcode >> 21) & 1) {
-            gen_op_rotr();
-            opn = "rotr";
-       } else {
+        switch ((ctx->opcode >> 21) & 0x1f) {
+        case 0:
             gen_op_srl();
             opn = "srl";
-       }
+            break;
+        case 1:
+            gen_op_rotr();
+            opn = "rotr";
+            break;
+        default:
+            MIPS_INVAL("invalid srl flag");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
         break;
 #ifdef TARGET_MIPS64
     case OPC_DSLL:
@@ -933,13 +1002,20 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
         opn = "dsra";
         break;
     case OPC_DSRL:
-       if ((ctx->opcode >> 21) & 1) {
-            gen_op_drotr();
-            opn = "drotr";
-       } else {
+        switch ((ctx->opcode >> 21) & 0x1f) {
+        case 0:
             gen_op_dsrl();
             opn = "dsrl";
-       }
+            break;
+        case 1:
+            gen_op_drotr();
+            opn = "drotr";
+            break;
+        default:
+            MIPS_INVAL("invalid dsrl flag");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
         break;
     case OPC_DSLL32:
         gen_op_dsll32();
@@ -950,13 +1026,20 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
         opn = "dsra32";
         break;
     case OPC_DSRL32:
-       if ((ctx->opcode >> 21) & 1) {
-            gen_op_drotr32();
-            opn = "drotr32";
-       } else {
+        switch ((ctx->opcode >> 21) & 0x1f) {
+        case 0:
             gen_op_dsrl32();
             opn = "dsrl32";
-       }
+            break;
+        case 1:
+            gen_op_drotr32();
+            opn = "drotr32";
+            break;
+        default:
+            MIPS_INVAL("invalid dsrl32 flag");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
         break;
 #endif
     default:
@@ -1068,13 +1151,20 @@ static void gen_arith (DisasContext *ctx, uint32_t opc,
         opn = "srav";
         break;
     case OPC_SRLV:
-       if ((ctx->opcode >> 6) & 1) {
-            gen_op_rotrv();
-            opn = "rotrv";
-       } else {
+        switch ((ctx->opcode >> 6) & 0x1f) {
+        case 0:
             gen_op_srlv();
             opn = "srlv";
-       }
+            break;
+        case 1:
+            gen_op_rotrv();
+            opn = "rotrv";
+            break;
+        default:
+            MIPS_INVAL("invalid srlv flag");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
         break;
 #ifdef TARGET_MIPS64
     case OPC_DSLLV:
@@ -1086,13 +1176,20 @@ static void gen_arith (DisasContext *ctx, uint32_t opc,
         opn = "dsrav";
         break;
     case OPC_DSRLV:
-       if ((ctx->opcode >> 6) & 1) {
-            gen_op_drotrv();
-            opn = "drotrv";
-       } else {
+        switch ((ctx->opcode >> 6) & 0x1f) {
+        case 0:
             gen_op_dsrlv();
             opn = "dsrlv";
-       }
+            break;
+        case 1:
+            gen_op_drotrv();
+            opn = "drotrv";
+            break;
+        default:
+            MIPS_INVAL("invalid dsrlv flag");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
         break;
 #endif
     default:
@@ -1426,7 +1523,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
         /* Jump to register */
         if (offset != 0 && offset != 16) {
             /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
-              others are reserved. */
+               others are reserved. */
             generate_exception(ctx, EXCP_RI);
             return;
         }
@@ -1470,14 +1567,14 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
         case OPC_BLTZALL: /* 0 < 0 likely */
             gen_op_set_T0(ctx->pc + 8);
             gen_op_store_T0_gpr(31);
-            gen_goto_tb(ctx, 0, ctx->pc + 4);
+            gen_goto_tb(ctx, 0, ctx->pc + 8);
             return;
         case OPC_BNEL:    /* rx != rx likely */
         case OPC_BGTZL:   /* 0 > 0 likely */
         case OPC_BLTZL:   /* 0 < 0 likely */
             /* Skip the instruction in the delay slot */
             MIPS_DEBUG("bnever and skip");
-            gen_goto_tb(ctx, 0, ctx->pc + 4);
+            gen_goto_tb(ctx, 0, ctx->pc + 8);
             return;
         case OPC_J:
             ctx->hflags |= MIPS_HFLAG_B;
@@ -1580,6 +1677,10 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
         likely:
             ctx->hflags |= MIPS_HFLAG_BL;
             break;
+        default:
+            MIPS_INVAL("conditional branch/jump");
+            generate_exception(ctx, EXCP_RI);
+            return;
         }
         gen_op_set_bcond();
     }
@@ -1590,7 +1691,6 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
         gen_op_set_T0(ctx->pc + 8);
         gen_op_store_T0_gpr(blink);
     }
-    return;
 }
 
 /* special3 bitfield operations */
@@ -4034,11 +4134,6 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd)
         opn = "mfc0";
         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);
         opn = "mtc0";
@@ -4053,11 +4148,6 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd)
         opn = "dmfc0";
         break;
     case OPC_DMTC0:
-        /* If we get an exception, we want to restart at next instruction */
-        /* XXX: breaks for dmtc in delay slot */
-        ctx->pc += 4;
-        save_cpu_state(ctx, 1);
-        ctx->pc -= 4;
         GEN_LOAD_REG_TN(T0, rt);
         gen_dmtc0(ctx, rd, ctx->opcode & 0x7);
         opn = "dmtc0";
@@ -4566,6 +4656,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
 
     /* make sure instructions are on a word boundary */
     if (ctx->pc & 0x3) {
+        env->CP0_BadVAddr = ctx->pc;
         generate_exception(ctx, EXCP_AdEL);
         return;
     }
@@ -4734,32 +4825,26 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
         case OPC_RDHWR:
             switch (rd) {
             case 0:
+                save_cpu_state(ctx, 1);
                 gen_op_rdhwr_cpunum();
                 break;
             case 1:
+                save_cpu_state(ctx, 1);
                 gen_op_rdhwr_synci_step();
                 break;
             case 2:
+                save_cpu_state(ctx, 1);
                 gen_op_rdhwr_cc();
                 break;
             case 3:
+                save_cpu_state(ctx, 1);
                 gen_op_rdhwr_ccres();
                 break;
             case 29:
 #if defined (CONFIG_USER_ONLY)
                 gen_op_tls_value ();
-#else
-                generate_exception(ctx, EXCP_RI);
-#endif
-                break;
-            case 30:
-                /* Implementation dependent */;
-                gen_op_rdhwr_unimpl30();
-                break;
-            case 31:
-                /* Implementation dependent */;
-                gen_op_rdhwr_unimpl31();
                 break;
+#endif
             default:            /* Invalid */
                 MIPS_INVAL("rdhwr");
                 generate_exception(ctx, EXCP_RI);
@@ -4817,6 +4902,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
         }
         break;
     case OPC_CP0:
+        save_cpu_state(ctx, 1);
         gen_op_cp0_enabled();
         op1 = MASK_CP0(ctx->opcode);
         switch (op1) {
@@ -4954,6 +5040,9 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
             gen_op_cp1_enabled();
             op1 = MASK_CP3(ctx->opcode);
             switch (op1) {
+            case OPC_PREFX:
+                /* treat as noop */
+                break;
             /* Not implemented */
             default:
                 generate_exception (ctx, EXCP_RI);
@@ -4993,7 +5082,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
         break;
     }
     if (ctx->hflags & MIPS_HFLAG_BMASK) {
-        int hflags = ctx->hflags;
+        int hflags = ctx->hflags & MIPS_HFLAG_BMASK;
         /* Branches completion */
         ctx->hflags &= ~MIPS_HFLAG_BMASK;
         ctx->bstate = BS_BRANCH;
This page took 0.032851 seconds and 4 git commands to generate.