summaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/cpu.h82
-rw-r--r--target-ppc/exec.h2
-rw-r--r--target-ppc/helper.c418
-rw-r--r--target-ppc/helper_regs.h142
-rw-r--r--target-ppc/op.c41
-rw-r--r--target-ppc/op_helper.c149
-rw-r--r--target-ppc/op_helper.h3
-rw-r--r--target-ppc/translate.c22
8 files changed, 398 insertions, 461 deletions
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)) {