diff options
Diffstat (limited to 'target-ppc')
-rw-r--r-- | target-ppc/cpu.h | 7 | ||||
-rw-r--r-- | target-ppc/op.c | 23 | ||||
-rw-r--r-- | target-ppc/op_helper.c | 16 | ||||
-rw-r--r-- | target-ppc/op_helper.h | 3 | ||||
-rw-r--r-- | target-ppc/translate.c | 196 |
5 files changed, 213 insertions, 32 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 791f305242..53f4af3d21 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -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); diff --git a/target-ppc/op.c b/target-ppc/op.c index fa8477ab9f..0694caf808 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -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) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index d75331722d..5223b1543f 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -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) diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index c5b4f2d19b..c7235cc3eb 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -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) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 612b0ad85a..3f7b799274 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -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; |