]> git.proxmox.com Git - mirror_qemu.git/commitdiff
Add missing PowerPC 64 instructions
authorj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Fri, 23 Mar 2007 09:45:27 +0000 (09:45 +0000)
committerj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Fri, 23 Mar 2007 09:45:27 +0000 (09:45 +0000)
PowerPC 64 fixes.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2530 c046a42c-6fe2-441c-8c8c-71466251a162

target-ppc/cpu.h
target-ppc/helper.c
target-ppc/op.c
target-ppc/op_helper.c
target-ppc/op_helper.h
target-ppc/op_mem.h
target-ppc/translate.c
target-ppc/translate_init.c

index 44dddc6c0f7a29a310b5ba621edef3735d078d8d..b70862ad813c14386ba186c29ba97431a676e017 100644 (file)
@@ -384,6 +384,8 @@ enum {
     PPC_SPE         = 0x0000000100000000ULL,
     /* PowerPC 2.03 SPE floating-point extension */
     PPC_SPEFPU      = 0x0000000200000000ULL,
+    /* SLB management */
+    PPC_SLBI        = 0x0000000400000000ULL,
 };
 
 /* CPU run-time flags (MMU and exception model) */
@@ -503,11 +505,16 @@ enum {
 #define PPC_INSNS_74xx (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_ALTIVEC |      \
                         PPC_MEM_TLBSYNC | PPC_TB)
 #define PPC_FLAGS_74xx (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_74xx)
+/* PowerPC 970 (aka G5) */
+#define PPC_INSNS_970  (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_FLOAT_OPT |    \
+                        PPC_ALTIVEC | PPC_MEM_TLBSYNC | PPC_TB |              \
+                        PPC_64B | PPC_64_BRIDGE | PPC_SLBI)
+#define PPC_FLAGS_970  (PPC_FLAGS_MMU_64B | PPC_FLAGS_EXCP_970)
 
 /* Default PowerPC will be 604/970 */
 #define PPC_INSNS_PPC32 PPC_INSNS_604
 #define PPC_FLAGS_PPC32 PPC_FLAGS_604
-#if 0
+#if 1
 #define PPC_INSNS_PPC64 PPC_INSNS_970
 #define PPC_FLAGS_PPC64 PPC_FLAGS_970
 #endif
@@ -801,7 +808,7 @@ uint32_t ppc_load_xer (CPUPPCState *env);
 void ppc_store_xer (CPUPPCState *env, uint32_t value);
 target_ulong do_load_msr (CPUPPCState *env);
 void do_store_msr (CPUPPCState *env, target_ulong value);
-void ppc_store_msr32 (CPUPPCState *env, uint32_t value);
+void ppc_store_msr_32 (CPUPPCState *env, uint32_t value);
 
 void do_compute_hflags (CPUPPCState *env);
 
index 4daef379f7d967d608005a32c44d62b025076f68..b86f8234e69fd4aeac8e4ef9c661a6190d646e86 100644 (file)
@@ -1203,9 +1203,10 @@ void do_store_msr (CPUPPCState *env, target_ulong value)
 }
 
 #if defined(TARGET_PPC64)
-void ppc_store_msr_32 (CPUPPCState *env, target_ulong value)
+void ppc_store_msr_32 (CPUPPCState *env, uint32_t value)
 {
-    do_store_msr(env, (uint32_t)value);
+    do_store_msr(env,
+                 (do_load_msr(env) & ~0xFFFFFFFFULL) | (value & 0xFFFFFFFF));
 }
 #endif
 
index 1e0584209e9c89f9e8082f212e15e9d83424c6cd..8bbbd62d47bbb94888697a1c6559e2c8fda2b100 100644 (file)
@@ -1721,6 +1721,29 @@ PPC_OP(fctiwz)
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+/* fcfid - fcfid. */
+PPC_OP(fcfid)
+{
+    do_fcfid();
+    RETURN();
+}
+
+/* fctid - fctid. */
+PPC_OP(fctid)
+{
+    do_fctid();
+    RETURN();
+}
+
+/* fctidz - fctidz. */
+PPC_OP(fctidz)
+{
+    do_fctidz();
+    RETURN();
+}
+#endif
+
 /***                         Floating-Point compare                        ***/
 /* fcmpu */
 PPC_OP(fcmpu)
@@ -1803,6 +1826,18 @@ void OPPROTO op_rfi_32 (void)
     do_rfi_32();
     RETURN();
 }
+
+void OPPROTO op_rfid (void)
+{
+    do_rfid();
+    RETURN();
+}
+
+void OPPROTO op_rfid_32 (void)
+{
+    do_rfid_32();
+    RETURN();
+}
 #endif
 #endif
 
index 45e4dde9d37444ff47bccc4466d5359cf8aa5aa9..55b5ca5653a9fa8d83586223daf974f1c9cf658a 100644 (file)
@@ -642,6 +642,42 @@ void do_fctiwz (void)
     FT0 = p.d;
 }
 
+#if defined(TARGET_PPC64)
+void do_fcfid (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.d = FT0;
+    FT0 = int64_to_float64(p.i, &env->fp_status);
+}
+
+void do_fctid (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.i = float64_to_int64(FT0, &env->fp_status);
+    FT0 = p.d;
+}
+
+void do_fctidz (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.i = float64_to_int64_round_to_zero(FT0, &env->fp_status);
+    FT0 = p.d;
+}
+
+#endif
+
 #if USE_PRECISE_EMULATION
 void do_fmadd (void)
 {
@@ -846,8 +882,12 @@ void do_fcmpo (void)
 void do_rfi (void)
 {
     env->nip = (target_ulong)(env->spr[SPR_SRR0] & ~0x00000003);
-    T0 = (target_ulong)(env->spr[SPR_SRR1] & ~0xFFFF0000UL);
+    T0 = (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL);
+#if defined(TARGET_PPC64)
+    ppc_store_msr_32(env, T0);
+#else
     do_store_msr(env, T0);
+#endif
 #if defined (DEBUG_OP)
     dump_rfi();
 #endif
@@ -859,6 +899,28 @@ void do_rfi_32 (void)
 {
     env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003);
     T0 = (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL);
+    ppc_store_msr_32(env, T0);
+#if defined (DEBUG_OP)
+    dump_rfi();
+#endif
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+
+void do_rfid (void)
+{
+    env->nip = (target_ulong)(env->spr[SPR_SRR0] & ~0x00000003);
+    T0 = (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL);
+    do_store_msr(env, T0);
+#if defined (DEBUG_OP)
+    dump_rfi();
+#endif
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+
+void do_rfid_32 (void)
+{
+    env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003);
+    T0 = (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL);
     do_store_msr(env, T0);
 #if defined (DEBUG_OP)
     dump_rfi();
index fc3d8af60488c7a07e95514fd1709fcb104a5632..f819a0d36c0b27c8619f6d46e12c104843eeab96 100644 (file)
@@ -101,6 +101,11 @@ void do_fnmadd (void);
 void do_fnmsub (void);
 void do_fctiw (void);
 void do_fctiwz (void);
+#if defined(TARGET_PPC64)
+void do_fcfid (void);
+void do_fctid (void);
+void do_fctidz (void);
+#endif
 void do_fcmpu (void);
 void do_fcmpo (void);
 
@@ -113,6 +118,8 @@ void do_td (int flags);
 void do_rfi (void);
 #if defined(TARGET_PPC64)
 void do_rfi_32 (void);
+void do_rfid (void);
+void do_rfid_32 (void);
 #endif
 void do_tlbia (void);
 void do_tlbie (void);
index f080abc41381c3c6f22eb23166157095f29e2f8e..a78aa62c480060448ef39aa68fca9e9a861b6548 100644 (file)
@@ -534,6 +534,17 @@ void OPPROTO glue(op_lwarx_64, MEMSUFFIX) (void)
     RETURN();
 }
 
+void OPPROTO glue(op_ldarx, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(EXCP_ALIGN);
+    } else {
+        T1 = glue(ldq, MEMSUFFIX)((uint32_t)T0);
+        regs->reserve = (uint32_t)T0;
+    }
+    RETURN();
+}
+
 void OPPROTO glue(op_ldarx_64, MEMSUFFIX) (void)
 {
     if (unlikely(T0 & 0x03)) {
@@ -569,6 +580,17 @@ void OPPROTO glue(op_lwarx_le_64, MEMSUFFIX) (void)
     RETURN();
 }
 
+void OPPROTO glue(op_ldarx_le, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(EXCP_ALIGN);
+    } else {
+        T1 = glue(ld64r, MEMSUFFIX)((uint32_t)T0);
+        regs->reserve = (uint32_t)T0;
+    }
+    RETURN();
+}
+
 void OPPROTO glue(op_ldarx_le_64, MEMSUFFIX) (void)
 {
     if (unlikely(T0 & 0x03)) {
@@ -615,6 +637,22 @@ void OPPROTO glue(op_stwcx_64, MEMSUFFIX) (void)
     RETURN();
 }
 
+void OPPROTO glue(op_stdcx, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(EXCP_ALIGN);
+    } else {
+        if (unlikely(regs->reserve != (uint32_t)T0)) {
+            env->crf[0] = xer_ov;
+        } else {
+            glue(stq, MEMSUFFIX)((uint32_t)T0, T1);
+            env->crf[0] = xer_ov | 0x02;
+        }
+    }
+    regs->reserve = -1;
+    RETURN();
+}
+
 void OPPROTO glue(op_stdcx_64, MEMSUFFIX) (void)
 {
     if (unlikely(T0 & 0x03)) {
@@ -665,6 +703,22 @@ void OPPROTO glue(op_stwcx_le_64, MEMSUFFIX) (void)
     RETURN();
 }
 
+void OPPROTO glue(op_stdcx_le, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(EXCP_ALIGN);
+    } else {
+        if (unlikely(regs->reserve != (uint32_t)T0)) {
+            env->crf[0] = xer_ov;
+        } else {
+            glue(st64r, MEMSUFFIX)((uint32_t)T0, T1);
+            env->crf[0] = xer_ov | 0x02;
+        }
+    }
+    regs->reserve = -1;
+    RETURN();
+}
+
 void OPPROTO glue(op_stdcx_le_64, MEMSUFFIX) (void)
 {
     if (unlikely(T0 & 0x03)) {
index 198fbf681536f7a7624ca3fab6a943a45192d843..7d382d6cab24f0f991ae130bb8dd3b104dc36b98 100644 (file)
@@ -1584,6 +1584,14 @@ GEN_FLOAT_B(ctiw, 0x0E, 0x00);
 GEN_FLOAT_B(ctiwz, 0x0F, 0x00);
 /* frsp */
 GEN_FLOAT_B(rsp, 0x0C, 0x00);
+#if defined(TARGET_PPC64)
+/* fcfid */
+GEN_FLOAT_B(cfid, 0x0E, 0x1A);
+/* fctid */
+GEN_FLOAT_B(ctid, 0x0E, 0x19);
+/* fctidz */
+GEN_FLOAT_B(ctidz, 0x0F, 0x19);
+#endif
 
 /***                         Floating-Point compare                        ***/
 /* fcmpo */
@@ -1996,8 +2004,8 @@ GEN_STS(h, 0x0C, PPC_INTEGER);
 GEN_STS(w, 0x04, PPC_INTEGER);
 #if defined(TARGET_PPC64)
 OP_ST_TABLE(d);
-GEN_STUX(d, 0x15, 0x01, PPC_64B);
-GEN_STX(d, 0x15, 0x00, PPC_64B);
+GEN_STUX(d, 0x15, 0x05, PPC_64B);
+GEN_STX(d, 0x15, 0x04, PPC_64B);
 GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000002, PPC_64B)
 {
     if (Rc(ctx->opcode)) {
@@ -2358,6 +2366,62 @@ GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
     op_stwcx();
 }
 
+#if defined(TARGET_PPC64)
+#define op_ldarx() (*gen_op_ldarx[ctx->mem_idx])()
+#define op_stdcx() (*gen_op_stdcx[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_ldarx[] = {
+    &gen_op_ldarx_raw,
+    &gen_op_ldarx_le_raw,
+    &gen_op_ldarx_64_raw,
+    &gen_op_ldarx_le_64_raw,
+};
+static GenOpFunc *gen_op_stdcx[] = {
+    &gen_op_stdcx_raw,
+    &gen_op_stdcx_le_raw,
+    &gen_op_stdcx_64_raw,
+    &gen_op_stdcx_le_64_raw,
+};
+#else
+static GenOpFunc *gen_op_ldarx[] = {
+    &gen_op_ldarx_user,
+    &gen_op_ldarx_le_user,
+    &gen_op_ldarx_kernel,
+    &gen_op_ldarx_le_kernel,
+    &gen_op_ldarx_64_user,
+    &gen_op_ldarx_le_64_user,
+    &gen_op_ldarx_64_kernel,
+    &gen_op_ldarx_le_64_kernel,
+};
+static GenOpFunc *gen_op_stdcx[] = {
+    &gen_op_stdcx_user,
+    &gen_op_stdcx_le_user,
+    &gen_op_stdcx_kernel,
+    &gen_op_stdcx_le_kernel,
+    &gen_op_stdcx_64_user,
+    &gen_op_stdcx_le_64_user,
+    &gen_op_stdcx_64_kernel,
+    &gen_op_stdcx_le_64_kernel,
+};
+#endif
+
+/* ldarx */
+GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_RES)
+{
+    gen_addr_reg_index(ctx);
+    op_ldarx();
+    gen_op_store_T1_gpr(rD(ctx->opcode));
+}
+
+/* stdcx. */
+GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_RES)
+{
+    gen_addr_reg_index(ctx);
+    gen_op_load_gpr_T1(rS(ctx->opcode));
+    op_stdcx();
+}
+#endif /* defined(TARGET_PPC64) */
+
 /* sync */
 GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM_SYNC)
 {
@@ -2807,6 +2871,26 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
 #endif
 }
 
+#if defined(TARGET_PPC64)
+GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_FLOW)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    /* Restore CPU state */
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    if (!ctx->sf_mode)
+        gen_op_rfid_32();
+    else
+        gen_op_rfid();
+    RET_CHG_FLOW(ctx);
+#endif
+}
+#endif
+
 /* sc */
 GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
 {
@@ -2978,6 +3062,25 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
 }
 
 /* mtmsr */
+#if defined(TARGET_PPC64)
+GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_MISC)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVREG(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVREG(ctx);
+        return;
+    }
+    gen_update_nip(ctx, ctx->nip);
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_store_msr();
+    /* Must stop the translation as machine state (may have) changed */
+    RET_CHG_FLOW(ctx);
+#endif
+}
+#endif
+
 GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
 {
 #if defined(CONFIG_USER_ONLY)
@@ -3313,6 +3416,41 @@ GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
 #endif
 }
 
+#if defined(TARGET_PPC64)
+/* slbia */
+GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        if (loglevel)
+            fprintf(logfile, "%s: ! supervisor\n", __func__);
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_slbia();
+    RET_STOP(ctx);
+#endif
+}
+
+/* slbie */
+GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rB(ctx->opcode));
+    gen_op_slbie();
+    RET_STOP(ctx);
+#endif
+}
+#endif
+
 /***                              External control                         ***/
 /* Optional: */
 #define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
index cba597672a0d0aaace5ed9d1f4e962a6c047ebf6..a8ebc0cb4f6b9b28c19ba7cdae3a4e91f9f4259e 100644 (file)
@@ -1716,7 +1716,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
     printf("%s: PVR %08x mask %08x => %08x\n", __func__,
            def->pvr, def->pvr_mask, def->pvr & def->pvr_mask);
     switch (def->pvr & def->pvr_mask) {
-        /* Embedded PowerPC from IBM                           */
+    /* Embedded PowerPC from IBM                           */
     case CPU_PPC_401A1:   /* 401 A1 family                 */
     case CPU_PPC_401B2:   /* 401 B2 family                 */
     case CPU_PPC_401C2:   /* 401 C2 family                 */
@@ -1833,7 +1833,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
         env->id_tlbs = 0;
         break;
 
-        /* Embedded PowerPC from Freescale                     */
+    /* Embedded PowerPC from Freescale                     */
 #if defined (TODO)
     case CPU_PPC_5xx:
         break;
@@ -1852,7 +1852,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
         break;
 #endif
 
-        /* XXX: Use MPC8540 PVR to implement a test PowerPC BookE target */
+    /* XXX: Use MPC8540 PVR to implement a test PowerPC BookE target */
     case CPU_PPC_e500v110:
     case CPU_PPC_e500v120:
     case CPU_PPC_e500v210:
@@ -1872,7 +1872,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
         break;
 #endif
 
-        /* 32 bits PowerPC                                     */
+    /* 32 bits PowerPC                                     */
     case CPU_PPC_601:     /* PowerPC 601                   */
         gen_spr_generic(env);
         gen_spr_ne_601(env);
@@ -2131,7 +2131,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
         break;
 
 #if defined (TODO)
-        /* G4 family */
+    /* G4 family */
     case CPU_PPC_7400:    /* PowerPC 7400                  */
     case CPU_PPC_7410C:   /* PowerPC 7410                  */
     case CPU_PPC_7410D:
@@ -2154,8 +2154,9 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
         break;
 #endif
 
+    /* 64 bits PowerPC                                     */
+#if defined (TARGET_PPC64)
 #if defined (TODO)
-        /* 64 bits PowerPC                                     */
     case CPU_PPC_620:     /* PowerPC 620                   */
     case CPU_PPC_630:     /* PowerPC 630 (Power 3)         */
     case CPU_PPC_631:     /* PowerPC 631 (Power 3+)        */
@@ -2163,6 +2164,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
     case CPU_PPC_POWER4P: /* Power 4+                      */
     case CPU_PPC_POWER5:  /* Power 5                       */
     case CPU_PPC_POWER5P: /* Power 5+                      */
+#endif
     case CPU_PPC_970:     /* PowerPC 970                   */
     case CPU_PPC_970FX10: /* PowerPC 970 FX                */
     case CPU_PPC_970FX20:
@@ -2171,16 +2173,20 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
     case CPU_PPC_970FX31:
     case CPU_PPC_970MP10: /* PowerPC 970 MP                */
     case CPU_PPC_970MP11:
+#if defined (TODO)
     case CPU_PPC_CELL10:  /* Cell family                   */
     case CPU_PPC_CELL20:
     case CPU_PPC_CELL30:
     case CPU_PPC_CELL31:
+#endif
+#if defined (TODO)
     case CPU_PPC_RS64:    /* Apache (RS64/A35)             */
     case CPU_PPC_RS64II:  /* NorthStar (RS64-II/A50)       */
     case CPU_PPC_RS64III: /* Pulsar (RS64-III)             */
     case CPU_PPC_RS64IV:  /* IceStar/IStar/SStar (RS64-IV) */
-        break;
 #endif
+        break;
+#endif /* defined (TARGET_PPC64) */
 
 #if defined (TODO)
         /* POWER                                               */
@@ -3412,6 +3418,7 @@ static ppc_def_t ppc_defs[] =
         },
 #endif
         /* 64 bits PowerPC */
+#if defined (TARGET_PPC64)
 #if defined (TODO)
         /* PowerPC 620 */
         {
@@ -3650,6 +3657,7 @@ static ppc_def_t ppc_defs[] =
             .msr_mask    = xxx,
         },
 #endif
+#endif /* defined (TARGET_PPC64) */
 #if defined (TODO)
         /* POWER2 */
         {