From 426613dbf8cd1120f9e47fb636c4c03bc1ef586c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 23 Mar 2007 09:45:27 +0000 Subject: [PATCH] Add missing PowerPC 64 instructions PowerPC 64 fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2530 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 11 ++- target-ppc/helper.c | 5 +- target-ppc/op.c | 35 +++++++++ target-ppc/op_helper.c | 64 +++++++++++++++- target-ppc/op_helper.h | 7 ++ target-ppc/op_mem.h | 54 ++++++++++++++ target-ppc/translate.c | 142 +++++++++++++++++++++++++++++++++++- target-ppc/translate_init.c | 22 ++++-- 8 files changed, 326 insertions(+), 14 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 44dddc6c0f..b70862ad81 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -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); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 4daef379f7..b86f8234e6 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -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 diff --git a/target-ppc/op.c b/target-ppc/op.c index 1e0584209e..8bbbd62d47 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -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 diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 45e4dde9d3..55b5ca5653 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -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(); diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index fc3d8af604..f819a0d36c 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -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); diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index f080abc413..a78aa62c48 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -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)) { diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 198fbf6815..7d382d6cab 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -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])() diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index cba597672a..a8ebc0cb4f 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -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 */ {