OSDN Git Service

* Update OEA environment, following the PowerPC 2.04 specification:
authorj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 30 Sep 2007 13:03:23 +0000 (13:03 +0000)
committerj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 30 Sep 2007 13:03:23 +0000 (13:03 +0000)
- New mtmsr/mtmsrd form that just update RI and EE bits
- New hrfid, lq and stq instructions
- Add support for supervisor and hypervisor modes process priority update
- Code provision for hypervisor SPR accesses
* Actually implement the wait instruction
* Bugfixes (missing RETURN in micro-op / missing #ifdef)

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

target-ppc/cpu.h
target-ppc/op.c
target-ppc/op_helper.c
target-ppc/op_helper.h
target-ppc/translate.c

index 791f305..53f4af3 100644 (file)
@@ -287,6 +287,7 @@ enum {
 
 #define PPC_INPUT(env) (env->bus_model)
 
+/*****************************************************************************/
 typedef struct ppc_def_t ppc_def_t;
 typedef struct opc_handler_t opc_handler_t;
 
@@ -306,6 +307,10 @@ struct ppc_spr_t {
 #if !defined(CONFIG_USER_ONLY)
     void (*oea_read)(void *opaque, int spr_num);
     void (*oea_write)(void *opaque, int spr_num);
+#if defined(TARGET_PPC64H)
+    void (*hea_read)(void *opaque, int spr_num);
+    void (*hea_write)(void *opaque, int spr_num);
+#endif
 #endif
     const unsigned char *name;
 };
@@ -607,7 +612,9 @@ target_ulong ppc_load_xer (CPUPPCState *env);
 void ppc_store_xer (CPUPPCState *env, target_ulong value);
 target_ulong do_load_msr (CPUPPCState *env);
 void do_store_msr (CPUPPCState *env, target_ulong value);
+#if defined(TARGET_PPC64)
 void ppc_store_msr_32 (CPUPPCState *env, uint32_t value);
+#endif
 
 void do_compute_hflags (CPUPPCState *env);
 void cpu_ppc_reset (void *opaque);
index fa8477a..0694caf 100644 (file)
@@ -355,6 +355,13 @@ void OPPROTO op_store_msr (void)
     RETURN();
 }
 
+void OPPROTO op_update_riee (void)
+{
+    msr_ri = (T0 >> MSR_RI) & 1;
+    msr_ee = (T0 >> MSR_EE) & 1;
+    RETURN();
+}
+
 #if defined (TARGET_PPC64)
 void OPPROTO op_store_msr_32 (void)
 {
@@ -1913,6 +1920,12 @@ void OPPROTO op_check_reservation_64 (void)
 }
 #endif
 
+void OPPROTO op_wait (void)
+{
+    env->halted = 1;
+    RETURN();
+}
+
 /* Return from interrupt */
 #if !defined(CONFIG_USER_ONLY)
 void OPPROTO op_rfi (void)
@@ -1928,6 +1941,14 @@ void OPPROTO op_rfid (void)
     RETURN();
 }
 #endif
+
+#if defined(TARGET_PPC64H)
+void OPPROTO op_hrfid (void)
+{
+    do_hrfid();
+    RETURN();
+}
+#endif
 #endif
 
 /* Trap word */
@@ -2557,6 +2578,7 @@ void OPPROTO op_store_40x_pit (void)
 void OPPROTO op_store_40x_dbcr0 (void)
 {
     store_40x_dbcr0(env, T0);
+    RETURN();
 }
 
 void OPPROTO op_store_40x_sler (void)
@@ -2576,7 +2598,6 @@ void OPPROTO op_store_booke_tsr (void)
     store_booke_tsr(env, T0);
     RETURN();
 }
-
 #endif /* !defined(CONFIG_USER_ONLY) */
 
 #if defined(TARGET_PPCEMB)
index d753317..5223b15 100644 (file)
@@ -1002,6 +1002,22 @@ void do_rfid (void)
     env->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
 #endif
+#if defined(TARGET_PPC64H)
+void do_hrfid (void)
+{
+    if (env->spr[SPR_HSRR1] & (1ULL << MSR_SF)) {
+        env->nip = (uint64_t)(env->spr[SPR_HSRR0] & ~0x00000003);
+        do_store_msr(env, (uint64_t)(env->spr[SPR_HSRR1] & ~0xFFFF0000UL));
+    } else {
+        env->nip = (uint32_t)(env->spr[SPR_HSRR0] & ~0x00000003);
+        do_store_msr(env, (uint32_t)(env->spr[SPR_HSRR1] & ~0xFFFF0000UL));
+    }
+#if defined (DEBUG_OP)
+    cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+#endif
 #endif
 
 void do_tw (int flags)
index c5b4f2d..c7235cc 100644 (file)
@@ -131,6 +131,9 @@ void do_rfi (void);
 #if defined(TARGET_PPC64)
 void do_rfid (void);
 #endif
+#if defined(TARGET_PPC64H)
+void do_hrfid (void);
+#endif
 void do_tlbia (void);
 void do_tlbie (void);
 #if defined(TARGET_PPC64)
index 612b0ad..3f7b799 100644 (file)
@@ -480,6 +480,8 @@ enum {
     PPC_FLOAT_EXT     = 0x0000080000000000ULL,
     /* New wait instruction (PowerPC 2.0x)              */
     PPC_WAIT          = 0x0000100000000000ULL,
+    /* New 64 bits extensions (PowerPC 2.0x)            */
+    PPC_64BX          = 0x0000200000000000ULL,
 };
 
 /*****************************************************************************/
@@ -1141,6 +1143,34 @@ GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
             /* Set process priority to normal */
             gen_op_store_pri(4);
             break;
+#if !defined(CONFIG_USER_ONLY)
+        case 31:
+            if (ctx->supervisor > 0) {
+                /* Set process priority to very low */
+                gen_op_store_pri(1);
+            }
+            break;
+        case 5:
+            if (ctx->supervisor > 0) {
+                /* Set process priority to medium-hight */
+                gen_op_store_pri(5);
+            }
+            break;
+        case 3:
+            if (ctx->supervisor > 0) {
+                /* Set process priority to high */
+                gen_op_store_pri(6);
+            }
+            break;
+#if defined(TARGET_PPC64H)
+        case 7:
+            if (ctx->supervisor > 1) {
+                /* Set process priority to very high */
+                gen_op_store_pri(7);
+            }
+            break;
+#endif
+#endif
         default:
             /* nop */
             break;
@@ -1902,12 +1932,11 @@ GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
 
 /***                           Addressing modes                            ***/
 /* Register indirect with immediate index : EA = (rA|0) + SIMM */
-static inline void gen_addr_imm_index (DisasContext *ctx, int maskl)
+static inline void gen_addr_imm_index (DisasContext *ctx, target_long maskl)
 {
     target_long simm = SIMM(ctx->opcode);
 
-    if (maskl)
-        simm &= ~0x03;
+    simm &= ~maskl;
     if (rA(ctx->opcode) == 0) {
         gen_set_T0(simm);
     } else {
@@ -2051,7 +2080,7 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, type)                   \
         return;                                                               \
     }                                                                         \
     if (type == PPC_64B)                                                      \
-        gen_addr_imm_index(ctx, 1);                                           \
+        gen_addr_imm_index(ctx, 0x03);                                        \
     else                                                                      \
         gen_addr_imm_index(ctx, 0);                                           \
     op_ldst(l##width);                                                        \
@@ -2116,7 +2145,7 @@ GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B)
             return;
         }
     }
-    gen_addr_imm_index(ctx, 1);
+    gen_addr_imm_index(ctx, 0x03);
     if (ctx->opcode & 0x02) {
         /* lwa (lwau is undefined) */
         op_ldst(lwa);
@@ -2128,6 +2157,38 @@ GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B)
     if (Rc(ctx->opcode))
         gen_op_store_T0_gpr(rA(ctx->opcode));
 }
+/* lq */
+GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    int ra, rd;
+
+    /* Restore CPU state */
+    if (unlikely(ctx->supervisor == 0)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    ra = rA(ctx->opcode);
+    rd = rD(ctx->opcode);
+    if (unlikely((rd & 1) || rd == ra)) {
+        GEN_EXCP_INVAL(ctx);
+        return;
+    }
+    if (unlikely(ctx->mem_idx & 1)) {
+        /* Little-endian mode is not handled */
+        GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
+        return;
+    }
+    gen_addr_imm_index(ctx, 0x0F);
+    op_ldst(ld);
+    gen_op_store_T1_gpr(rd);
+    gen_op_addi(8);
+    op_ldst(ld);
+    gen_op_store_T1_gpr(rd + 1);
+#endif
+}
 #endif
 
 /***                              Integer store                            ***/
@@ -2147,7 +2208,7 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type)                  \
         return;                                                               \
     }                                                                         \
     if (type == PPC_64B)                                                      \
-        gen_addr_imm_index(ctx, 1);                                           \
+        gen_addr_imm_index(ctx, 0x03);                                        \
     else                                                                      \
         gen_addr_imm_index(ctx, 0);                                           \
     gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
@@ -2193,19 +2254,50 @@ GEN_STS(w, 0x04, PPC_INTEGER);
 OP_ST_TABLE(d);
 GEN_STUX(d, 0x15, 0x05, PPC_64B);
 GEN_STX(d, 0x15, 0x04, PPC_64B);
-GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000002, PPC_64B)
+GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B)
 {
-    if (Rc(ctx->opcode)) {
-        if (unlikely(rA(ctx->opcode) == 0)) {
+    int rs;
+
+    rs = rS(ctx->opcode);
+    if ((ctx->opcode & 0x3) == 0x2) {
+#if defined(CONFIG_USER_ONLY)
+        GEN_EXCP_PRIVOPC(ctx);
+#else
+        /* stq */
+        if (unlikely(ctx->supervisor == 0)) {
+            GEN_EXCP_PRIVOPC(ctx);
+            return;
+        }
+        if (unlikely(rs & 1)) {
             GEN_EXCP_INVAL(ctx);
             return;
         }
+        if (unlikely(ctx->mem_idx & 1)) {
+            /* Little-endian mode is not handled */
+            GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
+            return;
+        }
+        gen_addr_imm_index(ctx, 0x03);
+        gen_op_load_gpr_T1(rs);
+        op_ldst(std);
+        gen_op_addi(8);
+        gen_op_load_gpr_T1(rs + 1);
+        op_ldst(std);
+#endif
+    } else {
+        /* std / stdu */
+        if (Rc(ctx->opcode)) {
+            if (unlikely(rA(ctx->opcode) == 0)) {
+                GEN_EXCP_INVAL(ctx);
+                return;
+            }
+        }
+        gen_addr_imm_index(ctx, 0x03);
+        gen_op_load_gpr_T1(rs);
+        op_ldst(std);
+        if (Rc(ctx->opcode))
+            gen_op_store_T0_gpr(rA(ctx->opcode));
     }
-    gen_addr_imm_index(ctx, 1);
-    gen_op_load_gpr_T1(rS(ctx->opcode));
-    op_ldst(std);
-    if (Rc(ctx->opcode))
-        gen_op_store_T0_gpr(rA(ctx->opcode));
 }
 #endif
 /***                Integer load and store with byte reverse               ***/
@@ -2620,8 +2712,8 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03BFF801, PPC_MEM_SYNC)
 GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT)
 {
     /* Stop translation, as the CPU is supposed to sleep from now */
-    /* XXX: TODO: handle this idle CPU case */
-    GEN_STOP(ctx);
+    gen_op_wait();
+    GEN_EXCP(ctx, EXCP_HLT, 1);
 }
 
 /***                         Floating-point load                           ***/
@@ -3077,6 +3169,23 @@ GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B)
 }
 #endif
 
+#if defined(TARGET_PPC64H)
+GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64B)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    /* Restore CPU state */
+    if (unlikely(ctx->supervisor <= 1)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_hrfid();
+    GEN_SYNC(ctx);
+#endif
+}
+#endif
+
 /* sc */
 GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW)
 {
@@ -3193,6 +3302,11 @@ static inline void gen_op_mfspr (DisasContext *ctx)
     uint32_t sprn = SPR(ctx->opcode);
 
 #if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64H)
+    if (ctx->supervisor == 2)
+        read_cb = ctx->spr_cb[sprn].hea_read;
+    else
+#endif
     if (ctx->supervisor)
         read_cb = ctx->spr_cb[sprn].oea_read;
     else
@@ -3253,7 +3367,7 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
 
 /* mtmsr */
 #if defined(TARGET_PPC64)
-GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_64B)
+GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVREG(ctx);
@@ -3262,12 +3376,17 @@ GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_64B)
         GEN_EXCP_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 */
-    /* Note that mtmsr is not always defined as context-synchronizing */
-    GEN_STOP(ctx);
+    if (ctx->opcode & 0x00010000) {
+        /* Special form that does not need any synchronisation */
+        gen_op_update_riee();
+    } else {
+        gen_update_nip(ctx, ctx->nip);
+        gen_op_store_msr();
+        /* Must stop the translation as machine state (may have) changed */
+        /* Note that mtmsr is not always defined as context-synchronizing */
+        GEN_STOP(ctx);
+    }
 #endif
 }
 #endif
@@ -3281,17 +3400,22 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
         GEN_EXCP_PRIVREG(ctx);
         return;
     }
-    gen_update_nip(ctx, ctx->nip);
     gen_op_load_gpr_T0(rS(ctx->opcode));
+    if (ctx->opcode & 0x00010000) {
+        /* Special form that does not need any synchronisation */
+        gen_op_update_riee();
+    } else {
+        gen_update_nip(ctx, ctx->nip);
 #if defined(TARGET_PPC64)
-    if (!ctx->sf_mode)
-        gen_op_store_msr_32();
-    else
+        if (!ctx->sf_mode)
+            gen_op_store_msr_32();
+        else
 #endif
-        gen_op_store_msr();
-    /* Must stop the translation as machine state (may have) changed */
-    /* Note that mtmsrd is not always defined as context-synchronizing */
-    GEN_STOP(ctx);
+            gen_op_store_msr();
+        /* Must stop the translation as machine state (may have) changed */
+        /* Note that mtmsrd is not always defined as context-synchronizing */
+        GEN_STOP(ctx);
+    }
 #endif
 }
 
@@ -3302,6 +3426,11 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
     uint32_t sprn = SPR(ctx->opcode);
 
 #if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64H)
+    if (ctx->supervisor == 2)
+        write_cb = ctx->spr_cb[sprn].hea_write;
+    else
+#endif
     if (ctx->supervisor)
         write_cb = ctx->spr_cb[sprn].oea_write;
     else
@@ -6011,7 +6140,12 @@ static inline int gen_intermediate_code_internal (CPUState *env,
     ctx.mem_idx |= msr_sf << 1;
 #endif
 #else
-    ctx.supervisor = 1 - msr_pr;
+#if defined(TARGET_PPC64H)
+    if (msr_pr == 0 && msr_hv == 1)
+        ctx.supervisor = 2;
+    else
+#endif
+        ctx.supervisor = 1 - msr_pr;
     ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le;
 #if defined(TARGET_PPC64)
     ctx.mem_idx |= msr_sf << 2;