diff options
author | j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-10-25 21:35:50 +0000 |
---|---|---|
committer | j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-10-25 21:35:50 +0000 |
commit | 0411a9725829d626bb0b2f11a461463c96061682 (patch) | |
tree | 105135188a4e2af4e3cf44518f5e2b14a7e83e01 | |
parent | 7ac256b8725304aabae78bf012c25b6416509c46 (diff) |
Gprof prooved the PowerPC emulation spent too much time in MSR load and store
routines. Coming back to a raw MSR storage model then speed-up the emulation.
Improve fast MSR updates (wrtee wrteei and mtriee cases).
Share rfi family instructions helpers code to avoid bug in duplicated code.
Allow entering halt mode as the result of a rfi instruction.
Add a new helper_regs.h file to avoid duplication of special registers
manipulation routines (currently XER and MSR).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3436 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | gdbstub.c | 4 | ||||
-rw-r--r-- | linux-user/main.c | 13 | ||||
-rw-r--r-- | monitor.c | 2 | ||||
-rw-r--r-- | target-ppc/cpu.h | 82 | ||||
-rw-r--r-- | target-ppc/exec.h | 2 | ||||
-rw-r--r-- | target-ppc/helper.c | 418 | ||||
-rw-r--r-- | target-ppc/helper_regs.h | 142 | ||||
-rw-r--r-- | target-ppc/op.c | 41 | ||||
-rw-r--r-- | target-ppc/op_helper.c | 149 | ||||
-rw-r--r-- | target-ppc/op_helper.h | 3 | ||||
-rw-r--r-- | target-ppc/translate.c | 22 |
11 files changed, 407 insertions, 471 deletions
@@ -300,7 +300,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) } /* nip, msr, ccr, lnk, ctr, xer, mq */ registers[96] = tswapl(env->nip); - registers[97] = tswapl(do_load_msr(env)); + registers[97] = tswapl(env->msr); tmp = 0; for (i = 0; i < 8; i++) tmp |= env->crf[i] << (32 - ((i + 1) * 4)); @@ -329,7 +329,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } /* nip, msr, ccr, lnk, ctr, xer, mq */ env->nip = tswapl(registers[96]); - do_store_msr(env, tswapl(registers[97])); + ppc_store_msr(env, tswapl(registers[97])); registers[98] = tswapl(registers[98]); for (i = 0; i < 8; i++) env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF; diff --git a/linux-user/main.c b/linux-user/main.c index 7c39121515..7590db80a6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2168,14 +2168,13 @@ int main(int argc, char **argv) } cpu_ppc_register(env, def); cpu_ppc_reset(env); - for (i = 0; i < 32; i++) { - if (i != 12 && i != 6 && i != 13) - env->msr[i] = (regs->msr >> i) & 1; - } -#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) - msr_sf = 1; + env->msr = regs->msr & ~((1 << 6) | (1 << 12) | (1 << 13)); +#if defined(TARGET_PPC64) +#if defined(TARGET_ABI32) + env->msr &= ~((target_ulong)1 << MSR_SF); #else - msr_sf = 0; + env->msr |= (target_ulong)1 << MSR_SF; +#endif #endif env->nip = regs->nip; for(i = 0; i < 32; i++) { @@ -1415,7 +1415,7 @@ static target_long monitor_get_msr (struct MonitorDef *md, int val) CPUState *env = mon_get_cpu(); if (!env) return 0; - return do_load_msr(env); + return env->msr; } static target_long monitor_get_xer (struct MonitorDef *md, int val) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index aeaacb2579..cf4a110ac4 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -368,7 +368,7 @@ union ppc_tlb_t { #define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC x */ #define MSR_FE1 8 /* Floating point exception mode 1 hflags */ #define MSR_AL 7 /* AL bit on POWER */ -#define MSR_EP 3 /* Exception prefix on 601 */ +#define MSR_EP 6 /* Exception prefix on 601 */ #define MSR_IR 5 /* Instruction relocate */ #define MSR_DR 4 /* Data relocate */ #define MSR_PE 3 /* Protection enable on 403 */ @@ -376,41 +376,42 @@ union ppc_tlb_t { #define MSR_PMM 2 /* Performance monitor mark on POWER x */ #define MSR_RI 1 /* Recoverable interrupt 1 */ #define MSR_LE 0 /* Little-endian mode 1 hflags */ -#define msr_sf env->msr[MSR_SF] -#define msr_isf env->msr[MSR_ISF] -#define msr_hv env->msr[MSR_HV] -#define msr_cm env->msr[MSR_CM] -#define msr_icm env->msr[MSR_ICM] -#define msr_ucle env->msr[MSR_UCLE] -#define msr_vr env->msr[MSR_VR] -#define msr_spe env->msr[MSR_SPE] -#define msr_ap env->msr[MSR_AP] -#define msr_sa env->msr[MSR_SA] -#define msr_key env->msr[MSR_KEY] -#define msr_pow env->msr[MSR_POW] -#define msr_tgpr env->msr[MSR_TGPR] -#define msr_ce env->msr[MSR_CE] -#define msr_ile env->msr[MSR_ILE] -#define msr_ee env->msr[MSR_EE] -#define msr_pr env->msr[MSR_PR] -#define msr_fp env->msr[MSR_FP] -#define msr_me env->msr[MSR_ME] -#define msr_fe0 env->msr[MSR_FE0] -#define msr_se env->msr[MSR_SE] -#define msr_dwe env->msr[MSR_DWE] -#define msr_uble env->msr[MSR_UBLE] -#define msr_be env->msr[MSR_BE] -#define msr_de env->msr[MSR_DE] -#define msr_fe1 env->msr[MSR_FE1] -#define msr_al env->msr[MSR_AL] -#define msr_ir env->msr[MSR_IR] -#define msr_dr env->msr[MSR_DR] -#define msr_pe env->msr[MSR_PE] -#define msr_ep env->msr[MSR_EP] -#define msr_px env->msr[MSR_PX] -#define msr_pmm env->msr[MSR_PMM] -#define msr_ri env->msr[MSR_RI] -#define msr_le env->msr[MSR_LE] + +#define msr_sf ((env->msr >> MSR_SF) & 1) +#define msr_isf ((env->msr >> MSR_ISF) & 1) +#define msr_hv ((env->msr >> MSR_HV) & 1) +#define msr_cm ((env->msr >> MSR_CM) & 1) +#define msr_icm ((env->msr >> MSR_ICM) & 1) +#define msr_ucle ((env->msr >> MSR_UCLE) & 1) +#define msr_vr ((env->msr >> MSR_VR) & 1) +#define msr_spe ((env->msr >> MSR_SE) & 1) +#define msr_ap ((env->msr >> MSR_AP) & 1) +#define msr_sa ((env->msr >> MSR_SA) & 1) +#define msr_key ((env->msr >> MSR_KEY) & 1) +#define msr_pow ((env->msr >> MSR_POW) & 1) +#define msr_tgpr ((env->msr >> MSR_TGPR) & 1) +#define msr_ce ((env->msr >> MSR_CE) & 1) +#define msr_ile ((env->msr >> MSR_ILE) & 1) +#define msr_ee ((env->msr >> MSR_EE) & 1) +#define msr_pr ((env->msr >> MSR_PR) & 1) +#define msr_fp ((env->msr >> MSR_FP) & 1) +#define msr_me ((env->msr >> MSR_ME) & 1) +#define msr_fe0 ((env->msr >> MSR_FE0) & 1) +#define msr_se ((env->msr >> MSR_SE) & 1) +#define msr_dwe ((env->msr >> MSR_DWE) & 1) +#define msr_uble ((env->msr >> MSR_UBLE) & 1) +#define msr_be ((env->msr >> MSR_BE) & 1) +#define msr_de ((env->msr >> MSR_DE) & 1) +#define msr_fe1 ((env->msr >> MSR_FE1) & 1) +#define msr_al ((env->msr >> MSR_AL) & 1) +#define msr_ep ((env->msr >> MSR_EP) & 1) +#define msr_ir ((env->msr >> MSR_IR) & 1) +#define msr_dr ((env->msr >> MSR_DR) & 1) +#define msr_pe ((env->msr >> MSR_PE) & 1) +#define msr_px ((env->msr >> MSR_PX) & 1) +#define msr_pmm ((env->msr >> MSR_PMM) & 1) +#define msr_ri ((env->msr >> MSR_RI) & 1) +#define msr_le ((env->msr >> MSR_LE) & 1) enum { POWERPC_FLAG_NONE = 0x00000000, @@ -468,7 +469,7 @@ struct CPUPPCState { /* Those ones are used in supervisor mode only */ /* machine state register */ - uint8_t msr[64]; + target_ulong msr; /* temporary general purpose registers */ ppc_gpr_t tgpr[4]; /* Used to speed-up TLB assist handlers */ @@ -639,13 +640,8 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value); #endif /* !defined(CONFIG_USER_ONLY) */ target_ulong ppc_load_xer (CPUPPCState *env); void ppc_store_xer (CPUPPCState *env, target_ulong value); -target_ulong do_load_msr (CPUPPCState *env); -int do_store_msr (CPUPPCState *env, target_ulong value); -#if defined(TARGET_PPC64) -int ppc_store_msr_32 (CPUPPCState *env, uint32_t value); -#endif +void ppc_store_msr (CPUPPCState *env, target_ulong value); -void do_compute_hflags (CPUPPCState *env); void cpu_ppc_reset (void *opaque); CPUPPCState *cpu_ppc_init (void); void cpu_ppc_close(CPUPPCState *env); diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 5685fd7a4b..5abcee0522 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -118,7 +118,7 @@ static always_inline int cpu_halted (CPUState *env) { if (!env->halted) return 0; - if (env->msr[MSR_EE] && (env->interrupt_request & CPU_INTERRUPT_HARD)) { + if (msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD)) { env->halted = 0; return 0; } diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 76312476a0..ea672bb4a2 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -27,10 +27,12 @@ #include "cpu.h" #include "exec-all.h" +#include "helper_regs.h" //#define DEBUG_MMU //#define DEBUG_BATS //#define DEBUG_SOFTWARE_TLB +//#define DUMP_PAGE_TABLES //#define DEBUG_EXCEPTIONS //#define FLUSH_ALL_TLBS @@ -447,7 +449,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, { target_ulong *BATlt, *BATut, *BATu, *BATl; target_ulong base, BEPIl, BEPIu, bl; - int i, pp; + int i, pp, pr; int ret = -1; #if defined (DEBUG_BATS) @@ -456,6 +458,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, type == ACCESS_CODE ? 'I' : 'D', virtual); } #endif + pr = msr_pr; switch (type) { case ACCESS_CODE: BATlt = env->IBAT[1]; @@ -490,8 +493,8 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, if ((virtual & 0xF0000000) == BEPIu && ((virtual & 0x0FFE0000) & ~bl) == BEPIl) { /* BAT matches */ - if ((msr_pr == 0 && (*BATu & 0x00000002)) || - (msr_pr == 1 && (*BATu & 0x00000001))) { + if (((pr == 0) && (*BATu & 0x00000002)) || + ((pr != 0) && (*BATu & 0x00000001))) { /* Get physical address */ ctx->raddr = (*BATl & 0xF0000000) | ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | @@ -851,9 +854,10 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, #if defined(TARGET_PPC64) int attr; #endif - int ds, vsid_sh, sdr_sh; + int ds, vsid_sh, sdr_sh, pr; int ret, ret2; + pr = msr_pr; #if defined(TARGET_PPC64) if (env->mmu_model == POWERPC_MMU_64B) { #if defined (DEBUG_MMU) @@ -864,8 +868,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr); if (ret < 0) return ret; - ctx->key = ((attr & 0x40) && msr_pr == 1) || - ((attr & 0x80) && msr_pr == 0) ? 1 : 0; + ctx->key = ((attr & 0x40) && (pr != 0)) || + ((attr & 0x80) && (pr == 0)) ? 1 : 0; ds = 0; ctx->nx = attr & 0x20 ? 1 : 0; vsid_mask = 0x00003FFFFFFFFF80ULL; @@ -877,8 +881,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, { sr = env->sr[eaddr >> 28]; page_mask = 0x0FFFFFFF; - ctx->key = (((sr & 0x20000000) && msr_pr == 1) || - ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; + ctx->key = (((sr & 0x20000000) && (pr != 0)) || + ((sr & 0x40000000) && (pr == 0))) ? 1 : 0; ds = sr & 0x80000000 ? 1 : 0; ctx->nx = sr & 0x10000000 ? 1 : 0; vsid = sr & 0x00FFFFFF; @@ -892,7 +896,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, " nip=0x" ADDRX " lr=0x" ADDRX " ir=%d dr=%d pr=%d %d t=%d\n", eaddr, (int)(eaddr >> 28), sr, env->nip, - env->lr, msr_ir, msr_dr, msr_pr, rw, type); + env->lr, (int)msr_ir, (int)msr_dr, pr != 0 ? 1 : 0, + rw, type); } #endif } @@ -981,7 +986,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, ret = ret2; } } -#if defined (DEBUG_MMU) +#if defined (DUMP_PAGE_TABLES) if (loglevel != 0) { target_phys_addr_t curaddr; uint32_t a0, a1, a2, a3; @@ -1157,10 +1162,11 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; - int i, ret, zsel, zpr; + int i, ret, zsel, zpr, pr; ret = -1; raddr = -1; + pr = msr_pr; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; if (ppcemb_tlb_check(env, tlb, &raddr, address, @@ -1177,7 +1183,7 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, /* Check execute enable bit */ switch (zpr) { case 0x2: - if (msr_pr) + if (pr != 0) goto check_perms; /* No break here */ case 0x3: @@ -1186,7 +1192,7 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, ret = 0; break; case 0x0: - if (msr_pr) { + if (pr != 0) { ctx->prot = 0; ret = -2; break; @@ -1248,7 +1254,7 @@ int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx, if (ppcemb_tlb_check(env, tlb, &raddr, address, env->spr[SPR_BOOKE_PID], 1, i) < 0) continue; - if (msr_pr) + if (msr_pr != 0) prot = tlb->prot & 0xF; else prot = (tlb->prot >> 4) & 0xF; @@ -1343,6 +1349,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw, int access_type, int check_BATs) { int ret; + #if 0 if (loglevel != 0) { fprintf(logfile, "%s\n", __func__); @@ -1949,180 +1956,18 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value) target_ulong ppc_load_xer (CPUPPCState *env) { - return (xer_so << XER_SO) | - (xer_ov << XER_OV) | - (xer_ca << XER_CA) | - (xer_bc << XER_BC) | - (xer_cmp << XER_CMP); + return hreg_load_xer(env); } void ppc_store_xer (CPUPPCState *env, target_ulong value) { - xer_so = (value >> XER_SO) & 0x01; - xer_ov = (value >> XER_OV) & 0x01; - xer_ca = (value >> XER_CA) & 0x01; - xer_cmp = (value >> XER_CMP) & 0xFF; - xer_bc = (value >> XER_BC) & 0x7F; -} - -/* Swap temporary saved registers with GPRs */ -static always_inline void swap_gpr_tgpr (CPUPPCState *env) -{ - ppc_gpr_t tmp; - - tmp = env->gpr[0]; - env->gpr[0] = env->tgpr[0]; - env->tgpr[0] = tmp; - tmp = env->gpr[1]; - env->gpr[1] = env->tgpr[1]; - env->tgpr[1] = tmp; - tmp = env->gpr[2]; - env->gpr[2] = env->tgpr[2]; - env->tgpr[2] = tmp; - tmp = env->gpr[3]; - env->gpr[3] = env->tgpr[3]; - env->tgpr[3] = tmp; + hreg_store_xer(env, value); } /* GDBstub can read and write MSR... */ -target_ulong do_load_msr (CPUPPCState *env) -{ - return -#if defined (TARGET_PPC64) - ((target_ulong)msr_sf << MSR_SF) | - ((target_ulong)msr_isf << MSR_ISF) | - ((target_ulong)msr_hv << MSR_HV) | -#endif - ((target_ulong)msr_ucle << MSR_UCLE) | - ((target_ulong)msr_vr << MSR_VR) | /* VR / SPE */ - ((target_ulong)msr_ap << MSR_AP) | - ((target_ulong)msr_sa << MSR_SA) | - ((target_ulong)msr_key << MSR_KEY) | - ((target_ulong)msr_pow << MSR_POW) | - ((target_ulong)msr_tgpr << MSR_TGPR) | /* TGPR / CE */ - ((target_ulong)msr_ile << MSR_ILE) | - ((target_ulong)msr_ee << MSR_EE) | - ((target_ulong)msr_pr << MSR_PR) | - ((target_ulong)msr_fp << MSR_FP) | - ((target_ulong)msr_me << MSR_ME) | - ((target_ulong)msr_fe0 << MSR_FE0) | - ((target_ulong)msr_se << MSR_SE) | /* SE / DWE / UBLE */ - ((target_ulong)msr_be << MSR_BE) | /* BE / DE */ - ((target_ulong)msr_fe1 << MSR_FE1) | - ((target_ulong)msr_al << MSR_AL) | - ((target_ulong)msr_ep << MSR_EP) | - ((target_ulong)msr_ir << MSR_IR) | - ((target_ulong)msr_dr << MSR_DR) | - ((target_ulong)msr_pe << MSR_PE) | - ((target_ulong)msr_px << MSR_PX) | /* PX / PMM */ - ((target_ulong)msr_ri << MSR_RI) | - ((target_ulong)msr_le << MSR_LE); -} - -int do_store_msr (CPUPPCState *env, target_ulong value) -{ - int enter_pm; - - value &= env->msr_mask; - if (((value >> MSR_IR) & 1) != msr_ir || - ((value >> MSR_DR) & 1) != msr_dr) { - /* Flush all tlb when changing translation mode */ - tlb_flush(env, 1); - env->interrupt_request |= CPU_INTERRUPT_EXITTB; - } -#if !defined (CONFIG_USER_ONLY) - if (unlikely((env->flags & POWERPC_FLAG_TGPR) && - ((value >> MSR_TGPR) & 1) != msr_tgpr)) { - /* Swap temporary saved registers with GPRs */ - swap_gpr_tgpr(env); - } - if (unlikely((value >> MSR_EP) & 1) != msr_ep) { - /* Change the exception prefix on PowerPC 601 */ - env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; - } -#endif -#if defined (TARGET_PPC64) - msr_sf = (value >> MSR_SF) & 1; - msr_isf = (value >> MSR_ISF) & 1; - msr_hv = (value >> MSR_HV) & 1; -#endif - msr_ucle = (value >> MSR_UCLE) & 1; - msr_vr = (value >> MSR_VR) & 1; /* VR / SPE */ - msr_ap = (value >> MSR_AP) & 1; - msr_sa = (value >> MSR_SA) & 1; - msr_key = (value >> MSR_KEY) & 1; - msr_pow = (value >> MSR_POW) & 1; - msr_tgpr = (value >> MSR_TGPR) & 1; /* TGPR / CE */ - msr_ile = (value >> MSR_ILE) & 1; - msr_ee = (value >> MSR_EE) & 1; - msr_pr = (value >> MSR_PR) & 1; - msr_fp = (value >> MSR_FP) & 1; - msr_me = (value >> MSR_ME) & 1; - msr_fe0 = (value >> MSR_FE0) & 1; - msr_se = (value >> MSR_SE) & 1; /* SE / DWE / UBLE */ - msr_be = (value >> MSR_BE) & 1; /* BE / DE */ - msr_fe1 = (value >> MSR_FE1) & 1; - msr_al = (value >> MSR_AL) & 1; - msr_ep = (value >> MSR_EP) & 1; - msr_ir = (value >> MSR_IR) & 1; - msr_dr = (value >> MSR_DR) & 1; - msr_pe = (value >> MSR_PE) & 1; - msr_px = (value >> MSR_PX) & 1; /* PX / PMM */ - msr_ri = (value >> MSR_RI) & 1; - msr_le = (value >> MSR_LE) & 1; - do_compute_hflags(env); - - enter_pm = 0; - switch (env->excp_model) { - case POWERPC_EXCP_603: - case POWERPC_EXCP_603E: - case POWERPC_EXCP_G2: - /* Don't handle SLEEP mode: we should disable all clocks... - * No dynamic power-management. - */ - if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00C00000) != 0) - enter_pm = 1; - break; - case POWERPC_EXCP_604: - if (msr_pow == 1) - enter_pm = 1; - break; - case POWERPC_EXCP_7x0: - if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0) - enter_pm = 1; - break; - default: - break; - } - - return enter_pm; -} - -#if defined(TARGET_PPC64) -int ppc_store_msr_32 (CPUPPCState *env, uint32_t value) -{ - return do_store_msr(env, (do_load_msr(env) & ~0xFFFFFFFFULL) | - (value & 0xFFFFFFFF)); -} -#endif - -void do_compute_hflags (CPUPPCState *env) +void ppc_store_msr (CPUPPCState *env, target_ulong value) { - /* Compute current hflags */ - env->hflags = (msr_vr << MSR_VR) | - (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | (msr_pr << MSR_PR) | - (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) | - (msr_be << MSR_BE) | (msr_fe1 << MSR_FE1) | (msr_le << MSR_LE); -#if defined (TARGET_PPC64) - env->hflags |= msr_cm << MSR_CM; - env->hflags |= (uint64_t)msr_sf << MSR_SF; - env->hflags |= (uint64_t)msr_hv << MSR_HV; - /* Precompute MMU index */ - if (msr_pr == 0 && msr_hv == 1) - env->mmu_idx = 2; - else -#endif - env->mmu_idx = 1 - msr_pr; + hreg_store_msr(env, value); } /*****************************************************************************/ @@ -2154,14 +1999,15 @@ static void dump_syscall (CPUState *env) static always_inline void powerpc_excp (CPUState *env, int excp_model, int excp) { - target_ulong msr, vector; + target_ulong msr, new_msr, vector; int srr0, srr1, asrr0, asrr1; if (loglevel & CPU_LOG_INT) { fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n", env->nip, excp, env->error_code); } - msr = do_load_msr(env); + msr = env->msr; + new_msr = msr; srr0 = SPR_SRR0; srr1 = SPR_SRR1; asrr0 = -1; @@ -2172,7 +2018,7 @@ static always_inline void powerpc_excp (CPUState *env, /* Should never happen */ return; case POWERPC_EXCP_CRITICAL: /* Critical input */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ switch (excp_model) { case POWERPC_EXCP_40x: srr0 = SPR_40x_SRR2; @@ -2203,10 +2049,10 @@ static always_inline void powerpc_excp (CPUState *env, env->halted = 1; env->interrupt_request |= CPU_INTERRUPT_EXITTB; } - msr_ri = 0; - msr_me = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); + new_msr &= ~((target_ulong)1 << MSR_ME); #if defined(TARGET_PPC64H) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif /* XXX: should also have something loaded in DAR / DSISR */ switch (excp_model) { @@ -2231,10 +2077,10 @@ static always_inline void powerpc_excp (CPUState *env, "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); } #endif - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_ISI: /* Instruction storage exception */ @@ -2244,25 +2090,25 @@ static always_inline void powerpc_excp (CPUState *env, "\n", msr, env->nip); } #endif - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= env->error_code; goto store_next; case POWERPC_EXCP_EXTERNAL: /* External input */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes0 == 1) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_ALIGN: /* Alignment exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif /* XXX: this is false */ /* Get rS/rD and rA from faulting opcode */ @@ -2279,10 +2125,10 @@ static always_inline void powerpc_excp (CPUState *env, #endif return; } - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00100000; /* Set FX */ @@ -2303,26 +2149,26 @@ static always_inline void powerpc_excp (CPUState *env, env->nip); } #endif - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00080000; break; case POWERPC_EXCP_PRIV: - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00040000; break; case POWERPC_EXCP_TRAP: - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00020000; break; @@ -2334,10 +2180,10 @@ static always_inline void powerpc_excp (CPUState *env, } goto store_next; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_current; case POWERPC_EXCP_SYSCALL: /* System call exception */ @@ -2352,20 +2198,20 @@ static always_inline void powerpc_excp (CPUState *env, if (loglevel & CPU_LOG_INT) { dump_syscall(env); } - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); goto store_current; case POWERPC_EXCP_DECR: /* Decrementer exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ @@ -2374,7 +2220,7 @@ static always_inline void powerpc_excp (CPUState *env, if (loglevel != 0) fprintf(logfile, "FIT exception\n"); #endif - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ #if defined (DEBUG_EXCEPTIONS) @@ -2389,13 +2235,13 @@ static always_inline void powerpc_excp (CPUState *env, default: break; } - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_DTLB: /* Data TLB error */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_ITLB: /* Instruction TLB error */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_DEBUG: /* Debug interrupt */ switch (excp_model) { @@ -2413,7 +2259,7 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; #if defined(TARGET_PPCEMB) case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_current; case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ /* XXX: TODO */ @@ -2426,7 +2272,7 @@ static always_inline void powerpc_excp (CPUState *env, "is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: TODO */ cpu_abort(env, "Performance counter exception is not implemented yet !\n"); @@ -2451,24 +2297,24 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; #endif /* defined(TARGET_PPCEMB) */ case POWERPC_EXCP_RESET: /* System reset exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; #if defined(TARGET_PPC64) case POWERPC_EXCP_DSEG: /* Data segment exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_ISEG: /* Instruction segment exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; #endif /* defined(TARGET_PPC64) */ @@ -2476,46 +2322,43 @@ static always_inline void powerpc_excp (CPUState *env, case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; #endif case POWERPC_EXCP_TRACE: /* Trace exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; #if defined(TARGET_PPC64H) case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; - /* XXX: TODO */ - cpu_abort(env, "Hypervisor instruction storage exception " - "is not implemented yet !\n"); + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; #endif /* defined(TARGET_PPC64H) */ case POWERPC_EXCP_VPU: /* Vector unavailable exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_current; case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ @@ -2523,7 +2366,7 @@ static always_inline void powerpc_excp (CPUState *env, if (loglevel != 0) fprintf(logfile, "PIT exception\n"); #endif - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_IO: /* IO error exception */ /* XXX: TODO */ @@ -2539,10 +2382,10 @@ static always_inline void powerpc_excp (CPUState *env, "is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ #if defined(TARGET_PPC64H) /* XXX: check this */ if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif switch (excp_model) { case POWERPC_EXCP_602: @@ -2560,10 +2403,10 @@ static always_inline void powerpc_excp (CPUState *env, } break; case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ #if defined(TARGET_PPC64H) /* XXX: check this */ if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif switch (excp_model) { case POWERPC_EXCP_602: @@ -2581,10 +2424,10 @@ static always_inline void powerpc_excp (CPUState *env, } break; case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ #if defined(TARGET_PPC64H) /* XXX: check this */ if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif switch (excp_model) { case POWERPC_EXCP_602: @@ -2593,8 +2436,10 @@ static always_inline void powerpc_excp (CPUState *env, case POWERPC_EXCP_G2: tlb_miss_tgpr: /* Swap temporary saved registers with GPRs */ - swap_gpr_tgpr(env); - msr_tgpr = 1; + if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { + new_msr |= (target_ulong)1 << MSR_TGPR; + hreg_swap_gpr_tgpr(env); + } goto tlb_miss; case POWERPC_EXCP_7x5: tlb_miss: @@ -2639,8 +2484,8 @@ static always_inline void powerpc_excp (CPUState *env, if (excp == POWERPC_EXCP_IFTLB) { es = "I"; en = 'I'; - miss = &env->spr[SPR_IMISS]; - cmp = &env->spr[SPR_ICMP]; + miss = &env->spr[SPR_TLBMISS]; + cmp = &env->spr[SPR_PTEHI]; } else { if (excp == POWERPC_EXCP_DLTLB) es = "DL"; @@ -2681,10 +2526,10 @@ static always_inline void powerpc_excp (CPUState *env, "is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif /* XXX: TODO */ cpu_abort(env, @@ -2725,23 +2570,26 @@ static always_inline void powerpc_excp (CPUState *env, if (asrr1 != -1) env->spr[asrr1] = env->spr[srr1]; /* If we disactivated any translation, flush TLBs */ - if (msr_ir || msr_dr) + if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR))) tlb_flush(env, 1); /* reload MSR with correct bits */ - msr_ee = 0; - msr_pr = 0; - msr_fp = 0; - msr_fe0 = 0; - msr_se = 0; - msr_be = 0; - msr_fe1 = 0; - msr_ir = 0; - msr_dr = 0; + new_msr &= ~((target_ulong)1 << MSR_EE); + new_msr &= ~((target_ulong)1 << MSR_PR); + new_msr &= ~((target_ulong)1 << MSR_FP); + new_msr &= ~((target_ulong)1 << MSR_FE0); + new_msr &= ~((target_ulong)1 << MSR_SE); + new_msr &= ~((target_ulong)1 << MSR_BE); + new_msr &= ~((target_ulong)1 << MSR_FE1); + new_msr &= ~((target_ulong)1 << MSR_IR); + new_msr &= ~((target_ulong)1 << MSR_DR); #if 0 /* Fix this: not on all targets */ - msr_pmm = 0; + new_msr &= ~((target_ulong)1 << MSR_PMM); #endif - msr_le = msr_ile; - do_compute_hflags(env); + new_msr &= ~((target_ulong)1 << MSR_LE); + if (msr_ile) + new_msr |= (target_ulong)1 << MSR_LE; + else + new_msr &= ~((target_ulong)1 << MSR_LE); /* Jump to handler */ vector = env->excp_vectors[excp]; if (vector == (target_ulong)-1) { @@ -2751,15 +2599,26 @@ static always_inline void powerpc_excp (CPUState *env, vector |= env->excp_prefix; #if defined(TARGET_PPC64) if (excp_model == POWERPC_EXCP_BOOKE) { - msr_cm = msr_icm; - if (!msr_cm) + if (!msr_icm) { + new_msr &= ~((target_ulong)1 << MSR_CM); vector = (uint32_t)vector; + } else { + new_msr |= (target_ulong)1 << MSR_CM; + } } else { - msr_sf = msr_isf; - if (!msr_sf) + if (!msr_isf) { + new_msr &= ~((target_ulong)1 << MSR_SF); vector = (uint32_t)vector; + } else { + new_msr |= (target_ulong)1 << MSR_SF; + } } #endif + /* XXX: we don't use hreg_store_msr here as already have treated + * any special case that could occur. Just store MSR and update hflags + */ + env->msr = new_msr; + hreg_compute_hflags(env); env->nip = vector; /* Reset exception state */ env->exception_index = POWERPC_EXCP_NONE; @@ -2773,11 +2632,11 @@ void do_interrupt (CPUState *env) void ppc_hw_interrupt (CPUPPCState *env) { -#if 1 +#if 0 if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: %p pending %08x req %08x me %d ee %d\n", __func__, env, env->pending_interrupts, - env->interrupt_request, msr_me, msr_ee); + env->interrupt_request, (int)msr_me, (int)msr_ee); } #endif /* External reset */ @@ -2801,7 +2660,7 @@ void ppc_hw_interrupt (CPUPPCState *env) } #endif #if defined(TARGET_PPC64H) - if ((msr_ee != 0 || msr_hv == 0 || msr_pr == 1) & hdice != 0) { + if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) & hdice != 0) { /* Hypervisor decrementer exception */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); @@ -2933,34 +2792,31 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr) void cpu_ppc_reset (void *opaque) { CPUPPCState *env; - int i; + target_ulong msr; env = opaque; - /* XXX: some of those flags initialisation values could depend - * on the actual PowerPC implementation - */ - for (i = 0; i < 63; i++) - env->msr[i] = 0; + msr = (target_ulong)0; #if defined(TARGET_PPC64) - msr_hv = 0; /* Should be 1... */ + msr |= (target_ulong)0 << MSR_HV; /* Should be 1... */ #endif - msr_ap = 0; /* TO BE CHECKED */ - msr_sa = 0; /* TO BE CHECKED */ - msr_ep = 1; + msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */ + msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */ + msr |= (target_ulong)1 << MSR_EP; #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ - msr_se = 1; - msr_be = 1; + msr |= (target_ulong)1 << MSR_SE; + msr |= (target_ulong)1 << MSR_BE; #endif #if defined(CONFIG_USER_ONLY) - msr_fp = 1; /* Allow floating point exceptions */ - msr_pr = 1; + msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */ + msr |= (target_ulong)1 << MSR_PR; #else env->nip = env->hreset_vector | env->excp_prefix; if (env->mmu_model != POWERPC_MMU_REAL_4xx) ppc_tlb_invalidate_all(env); #endif - do_compute_hflags(env); + env->msr = msr; + hreg_compute_hflags(env); env->reserve = -1; /* Be sure no exception or interrupt is pending */ env->pending_interrupts = 0; diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h new file mode 100644 index 0000000000..75a3dddd52 --- /dev/null +++ b/target-ppc/helper_regs.h @@ -0,0 +1,142 @@ +/* + * PowerPC emulation special registers manipulation helpers for qemu. + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined(__HELPER_REGS_H__) +#define __HELPER_REGS_H__ + +static always_inline target_ulong hreg_load_xer (CPUPPCState *env) +{ + return (xer_so << XER_SO) | + (xer_ov << XER_OV) | + (xer_ca << XER_CA) | + (xer_bc << XER_BC) | + (xer_cmp << XER_CMP); +} + +static always_inline void hreg_store_xer (CPUPPCState *env, target_ulong value) +{ + xer_so = (value >> XER_SO) & 0x01; + xer_ov = (value >> XER_OV) & 0x01; + xer_ca = (value >> XER_CA) & 0x01; + xer_cmp = (value >> XER_CMP) & 0xFF; + xer_bc = (value >> XER_BC) & 0x7F; +} + +/* Swap temporary saved registers with GPRs */ +static always_inline void hreg_swap_gpr_tgpr (CPUPPCState *env) +{ + ppc_gpr_t tmp; + + tmp = env->gpr[0]; + env->gpr[0] = env->tgpr[0]; + env->tgpr[0] = tmp; + tmp = env->gpr[1]; + env->gpr[1] = env->tgpr[1]; + env->tgpr[1] = tmp; + tmp = env->gpr[2]; + env->gpr[2] = env->tgpr[2]; + env->tgpr[2] = tmp; + tmp = env->gpr[3]; + env->gpr[3] = env->tgpr[3]; + env->tgpr[3] = tmp; +} + +static always_inline void hreg_compute_hflags (CPUPPCState *env) +{ + target_ulong hflags_mask; + + /* We 'forget' FE0 & FE1: we'll never generate imprecise exceptions */ + hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) | + (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) | + (1 << MSR_LE); +#if defined (TARGET_PPC64) + hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF); +#if defined (TARGET_PPC64H) + hflags_mask |= 1ULL << MSR_HV; + /* Precompute MMU index */ + if (msr_pr == 0 && msr_hv != 0) + env->mmu_idx = 2; + else +#endif +#endif + env->mmu_idx = 1 - msr_pr; + env->hflags = env->msr & hflags_mask; +} + +static always_inline int hreg_store_msr (CPUPPCState *env, target_ulong value) +{ + int enter_pm, excp; + + excp = 0; + value &= env->msr_mask; +#if !defined (CONFIG_USER_ONLY) + if (((value >> MSR_IR) & 1) != msr_ir || + ((value >> MSR_DR) & 1) != msr_dr) { + /* Flush all tlb when changing translation mode */ + tlb_flush(env, 1); + excp = POWERPC_EXCP_NONE; + env->interrupt_request |= CPU_INTERRUPT_EXITTB; + } + if (unlikely((env->flags & POWERPC_FLAG_TGPR) && + ((value ^ env->msr) & (1 << MSR_TGPR)))) { + /* Swap temporary saved registers with GPRs */ + hreg_swap_gpr_tgpr(env); + } + if (unlikely((value >> MSR_EP) & 1) != msr_ep) { + /* Change the exception prefix on PowerPC 601 */ + env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; + } +#endif + env->msr = value; + hreg_compute_hflags(env); + enter_pm = 0; +#if !defined (CONFIG_USER_ONLY) + if (unlikely(msr_pow == 1)) { + switch (env->excp_model) { + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: + /* Don't handle SLEEP mode: we should disable all clocks... + * No dynamic power-management. + */ + if ((env->spr[SPR_HID0] & 0x00C00000) != 0) + enter_pm = 1; + break; + case POWERPC_EXCP_604: + enter_pm = 1; + break; + case POWERPC_EXCP_7x0: + if ((env->spr[SPR_HID0] & 0x00E00000) != 0) + enter_pm = 1; + break; + default: + break; + } + if (enter_pm) { + env->halted = 1; + excp = EXCP_HALTED; + } + } +#endif + + return excp; +} + +#endif /* !defined(__HELPER_REGS_H__) */ diff --git a/target-ppc/op.c b/target-ppc/op.c index 4889ad476f..0030c14661 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -22,6 +22,7 @@ #include "config.h" #include "exec.h" +#include "helper_regs.h" #include "op_helper.h" #define REG 0 @@ -284,13 +285,13 @@ void OPPROTO op_store_xer_bc (void) void OPPROTO op_load_xer (void) { - do_load_xer(); + T0 = hreg_load_xer(env); RETURN(); } void OPPROTO op_store_xer (void) { - do_store_xer(); + hreg_store_xer(env, T0); RETURN(); } @@ -358,37 +359,36 @@ void OPPROTO op_store_asr (void) void OPPROTO op_load_msr (void) { - T0 = do_load_msr(env); + T0 = env->msr; RETURN(); } void OPPROTO op_store_msr (void) { - if (do_store_msr(env, T0)) { - env->halted = 1; - do_raise_exception(EXCP_HLT); - } + do_store_msr(); RETURN(); } -void OPPROTO op_update_riee (void) +#if defined (TARGET_PPC64) +void OPPROTO op_store_msr_32 (void) { - msr_ri = (T0 >> MSR_RI) & 1; - msr_ee = (T0 >> MSR_EE) & 1; + T0 = (env->msr & ~0xFFFFFFFFULL) | (T0 & 0xFFFFFFFF); + do_store_msr(); RETURN(); } +#endif -#if defined (TARGET_PPC64) -void OPPROTO op_store_msr_32 (void) +void OPPROTO op_update_riee (void) { - if (ppc_store_msr_32(env, T0)) { - env->halted = 1; - do_raise_exception(EXCP_HLT); - } + /* We don't call do_store_msr here as we won't trigger + * any special case nor change hflags + */ + T0 &= (1 << MSR_RI) | (1 << MSR_EE); + env->msr &= ~(1 << MSR_RI) | (1 << MSR_EE); + env->msr |= T0; RETURN(); } #endif -#endif /* SPR */ void OPPROTO op_load_spr (void) @@ -2517,7 +2517,12 @@ void OPPROTO op_rfmci (void) void OPPROTO op_wrte (void) { - msr_ee = T0 >> 16; + /* We don't call do_store_msr here as we won't trigger + * any special case nor change hflags + */ + T0 &= 1 << MSR_EE; + env->msr &= ~(1 << MSR_EE); + env->msr |= T0; RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index f5331bace4..c654b139cc 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -19,6 +19,7 @@ */ #include "exec.h" +#include "helper_regs.h" #include "op_helper.h" #define MEMSUFFIX _raw @@ -98,24 +99,6 @@ void do_store_cr (uint32_t mask) } } -void do_load_xer (void) -{ - T0 = (xer_so << XER_SO) | - (xer_ov << XER_OV) | - (xer_ca << XER_CA) | - (xer_bc << XER_BC) | - (xer_cmp << XER_CMP); -} - -void do_store_xer (void) -{ - xer_so = (T0 >> XER_SO) & 0x01; - xer_ov = (T0 >> XER_OV) & 0x01; - xer_ca = (T0 >> XER_CA) & 0x01; - xer_cmp = (T0 >> XER_CMP) & 0xFF; - xer_bc = (T0 >> XER_BC) & 0x7F; -} - #if defined(TARGET_PPC64) void do_store_pri (int prio) { @@ -970,56 +953,63 @@ void do_fcmpo (void) #if !defined (CONFIG_USER_ONLY) void cpu_dump_rfi (target_ulong RA, target_ulong msr); -void do_rfi (void) + +void do_store_msr (void) +{ + T0 = hreg_store_msr(env, T0); + if (T0 != 0) { + env->interrupt_request |= CPU_INTERRUPT_EXITTB; + do_raise_exception(T0); + } +} + +static always_inline void __do_rfi (target_ulong nip, target_ulong msr, + target_ulong msrm, int keep_msrh) { #if defined(TARGET_PPC64) - if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) { - env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003); - do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + if (msr & (1ULL << MSR_SF)) { + nip = (uint64_t)nip; + msr &= (uint64_t)msrm; } else { - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - ppc_store_msr_32(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + nip = (uint32_t)nip; + msr = (uint32_t)(msr & msrm); + if (keep_msrh) + msr |= env->msr & ~((uint64_t)0xFFFFFFFF); } #else - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + nip = (uint32_t)nip; + msr &= (uint32_t)msrm; #endif + /* XXX: beware: this is false if VLE is supported */ + env->nip = nip & ~((target_ulong)0x00000003); + hreg_store_msr(env, msr); #if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); + cpu_dump_rfi(env->nip, env->msr); #endif + /* No need to raise an exception here, + * as rfi is always the last insn of a TB + */ env->interrupt_request |= CPU_INTERRUPT_EXITTB; } +void do_rfi (void) +{ + __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0xFFFF0000), 1); +} + #if defined(TARGET_PPC64) void do_rfid (void) { - if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) { - env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003); - do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); - } else { - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); - } -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0xFFFF0000), 0); } #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; + __do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1], + ~((target_ulong)0xFFFF0000), 0); } #endif #endif @@ -1214,13 +1204,7 @@ void do_POWER_rac (void) void do_POWER_rfsvc (void) { - env->nip = env->lr & ~0x00000003UL; - T0 = env->ctr & 0x0000FFFFUL; - do_store_msr(env, T0); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + __do_rfi(env->lr, env->ctr, 0x0000FFFF, 0); } /* PowerPC 601 BAT management helper */ @@ -1332,63 +1316,26 @@ void do_store_dcr (void) #if !defined(CONFIG_USER_ONLY) void do_40x_rfci (void) { - env->nip = env->spr[SPR_40x_SRR2]; - do_store_msr(env, env->spr[SPR_40x_SRR3] & ~0xFFFF0000); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request = CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3], + ~((target_ulong)0xFFFF0000), 0); } void do_rfci (void) { -#if defined(TARGET_PPC64) - if (env->spr[SPR_BOOKE_CSRR1] & (1 << MSR_CM)) { - env->nip = (uint64_t)env->spr[SPR_BOOKE_CSRR0]; - } else -#endif - { - env->nip = (uint32_t)env->spr[SPR_BOOKE_CSRR0]; - } - do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_CSRR1] & ~0x3FFF0000); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request = CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1, + ~((target_ulong)0x3FFF0000), 0); } void do_rfdi (void) { -#if defined(TARGET_PPC64) - if (env->spr[SPR_BOOKE_DSRR1] & (1 << MSR_CM)) { - env->nip = (uint64_t)env->spr[SPR_BOOKE_DSRR0]; - } else -#endif - { - env->nip = (uint32_t)env->spr[SPR_BOOKE_DSRR0]; - } - do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_DSRR1] & ~0x3FFF0000); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request = CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1, + ~((target_ulong)0x3FFF0000), 0); } void do_rfmci (void) { -#if defined(TARGET_PPC64) - if (env->spr[SPR_BOOKE_MCSRR1] & (1 << MSR_CM)) { - env->nip = (uint64_t)env->spr[SPR_BOOKE_MCSRR0]; - } else -#endif - { - env->nip = (uint32_t)env->spr[SPR_BOOKE_MCSRR0]; - } - do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_MCSRR1] & ~0x3FFF0000); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request = CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1, + ~((target_ulong)0x3FFF0000), 0); } void do_load_403_pb (int num) diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 4688bc2fa4..e260b4ff97 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -57,8 +57,6 @@ void do_print_mem_EA (target_ulong EA); /* Registers load and stores */ void do_load_cr (void); void do_store_cr (uint32_t mask); -void do_load_xer (void); -void do_store_xer (void); #if defined(TARGET_PPC64) void do_store_pri (int prio); #endif @@ -129,6 +127,7 @@ void do_tw (int flags); void do_td (int flags); #endif #if !defined(CONFIG_USER_ONLY) +void do_store_msr (void); void do_rfi (void); #if defined(TARGET_PPC64) void do_rfid (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 6f2a9721f2..817045de8c 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6538,18 +6538,10 @@ GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPEFPU); // GEN_OPCODE_MARK(end); #include "translate_init.c" +#include "helper_regs.h" /*****************************************************************************/ /* Misc PowerPC helpers */ -static always_inline uint32_t load_xer (CPUState *env) -{ - return (xer_so << XER_SO) | - (xer_ov << XER_OV) | - (xer_ca << XER_CA) | - (xer_bc << XER_BC) | - (xer_cmp << XER_CMP); -} - void cpu_dump_state (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) @@ -6566,8 +6558,8 @@ void cpu_dump_state (CPUState *env, FILE *f, int i; - cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX "\n", - env->nip, env->lr, env->ctr); + cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX " idx %d\n", + env->nip, env->lr, env->ctr, env->mmu_idx); cpu_fprintf(f, "MSR " REGX FILL " XER %08x " #if !defined(NO_TIMER_DUMP) "TB %08x %08x " @@ -6576,7 +6568,7 @@ void cpu_dump_state (CPUState *env, FILE *f, #endif #endif "\n", - do_load_msr(env), load_xer(env) + env->msr, hreg_load_xer(env) #if !defined(NO_TIMER_DUMP) , cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env) #if !defined(CONFIG_USER_ONLY) @@ -6753,7 +6745,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); fprintf(logfile, "nip=" ADDRX " super=%d ir=%d\n", - ctx.nip, 1 - msr_pr, msr_ir); + ctx.nip, supervisor, (int)msr_ir); } #endif ctx.opcode = ldl_code(ctx.nip); @@ -6787,12 +6779,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, fprintf(logfile, "invalid/unsupported opcode: " "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); + opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); } else { printf("invalid/unsupported opcode: " "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); + opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); } } else { if (unlikely((ctx.opcode & handler->inval) != 0)) { |