From b327c654e5c11dac8a8dff3cc379b2599a288eca Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:21 +0000 Subject: [PATCH 01/72] ppc: Fix coding style in op_helper.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit op_helper.c will be split by the next patches, fix style issues before that. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/op_helper.c | 1257 +++++++++++++++++++++++----------------- 1 file changed, 731 insertions(+), 526 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 4ef2332a5a..d9f7a8beda 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1,5 +1,5 @@ /* - * PowerPC emulation helpers for qemu. + * PowerPC emulation helpers for QEMU. * * Copyright (c) 2003-2007 Jocelyn Mayer * @@ -42,7 +42,7 @@ /*****************************************************************************/ /* Exceptions processing helpers */ -void helper_raise_exception_err (uint32_t exception, uint32_t error_code) +void helper_raise_exception_err(uint32_t exception, uint32_t error_code) { #if 0 printf("Raise exception %3x code : %d\n", exception, error_code); @@ -52,116 +52,116 @@ void helper_raise_exception_err (uint32_t exception, uint32_t error_code) cpu_loop_exit(env); } -void helper_raise_exception (uint32_t exception) +void helper_raise_exception(uint32_t exception) { helper_raise_exception_err(exception, 0); } /*****************************************************************************/ /* SPR accesses */ -void helper_load_dump_spr (uint32_t sprn) +void helper_load_dump_spr(uint32_t sprn) { qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn, env->spr[sprn]); } -void helper_store_dump_spr (uint32_t sprn) +void helper_store_dump_spr(uint32_t sprn) { qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn, env->spr[sprn]); } -target_ulong helper_load_tbl (void) +target_ulong helper_load_tbl(void) { return (target_ulong)cpu_ppc_load_tbl(env); } -target_ulong helper_load_tbu (void) +target_ulong helper_load_tbu(void) { return cpu_ppc_load_tbu(env); } -target_ulong helper_load_atbl (void) +target_ulong helper_load_atbl(void) { return (target_ulong)cpu_ppc_load_atbl(env); } -target_ulong helper_load_atbu (void) +target_ulong helper_load_atbu(void) { return cpu_ppc_load_atbu(env); } #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) -target_ulong helper_load_purr (void) +target_ulong helper_load_purr(void) { return (target_ulong)cpu_ppc_load_purr(env); } #endif -target_ulong helper_load_601_rtcl (void) +target_ulong helper_load_601_rtcl(void) { return cpu_ppc601_load_rtcl(env); } -target_ulong helper_load_601_rtcu (void) +target_ulong helper_load_601_rtcu(void) { return cpu_ppc601_load_rtcu(env); } #if !defined(CONFIG_USER_ONLY) -#if defined (TARGET_PPC64) -void helper_store_asr (target_ulong val) +#if defined(TARGET_PPC64) +void helper_store_asr(target_ulong val) { ppc_store_asr(env, val); } #endif -void helper_store_sdr1 (target_ulong val) +void helper_store_sdr1(target_ulong val) { ppc_store_sdr1(env, val); } -void helper_store_tbl (target_ulong val) +void helper_store_tbl(target_ulong val) { cpu_ppc_store_tbl(env, val); } -void helper_store_tbu (target_ulong val) +void helper_store_tbu(target_ulong val) { cpu_ppc_store_tbu(env, val); } -void helper_store_atbl (target_ulong val) +void helper_store_atbl(target_ulong val) { cpu_ppc_store_atbl(env, val); } -void helper_store_atbu (target_ulong val) +void helper_store_atbu(target_ulong val) { cpu_ppc_store_atbu(env, val); } -void helper_store_601_rtcl (target_ulong val) +void helper_store_601_rtcl(target_ulong val) { cpu_ppc601_store_rtcl(env, val); } -void helper_store_601_rtcu (target_ulong val) +void helper_store_601_rtcu(target_ulong val) { cpu_ppc601_store_rtcu(env, val); } -target_ulong helper_load_decr (void) +target_ulong helper_load_decr(void) { return cpu_ppc_load_decr(env); } -void helper_store_decr (target_ulong val) +void helper_store_decr(target_ulong val) { cpu_ppc_store_decr(env, val); } -void helper_store_hid0_601 (target_ulong val) +void helper_store_hid0_601(target_ulong val) { target_ulong hid0; @@ -178,7 +178,7 @@ void helper_store_hid0_601 (target_ulong val) env->spr[SPR_HID0] = (uint32_t)val; } -void helper_store_403_pbr (uint32_t num, target_ulong value) +void helper_store_403_pbr(uint32_t num, target_ulong value) { if (likely(env->pb[num] != value)) { env->pb[num] = value; @@ -187,62 +187,62 @@ void helper_store_403_pbr (uint32_t num, target_ulong value) } } -target_ulong helper_load_40x_pit (void) +target_ulong helper_load_40x_pit(void) { return load_40x_pit(env); } -void helper_store_40x_pit (target_ulong val) +void helper_store_40x_pit(target_ulong val) { store_40x_pit(env, val); } -void helper_store_40x_dbcr0 (target_ulong val) +void helper_store_40x_dbcr0(target_ulong val) { store_40x_dbcr0(env, val); } -void helper_store_40x_sler (target_ulong val) +void helper_store_40x_sler(target_ulong val) { store_40x_sler(env, val); } -void helper_store_booke_tcr (target_ulong val) +void helper_store_booke_tcr(target_ulong val) { store_booke_tcr(env, val); } -void helper_store_booke_tsr (target_ulong val) +void helper_store_booke_tsr(target_ulong val) { store_booke_tsr(env, val); } -void helper_store_ibatu (uint32_t nr, target_ulong val) +void helper_store_ibatu(uint32_t nr, target_ulong val) { ppc_store_ibatu(env, nr, val); } -void helper_store_ibatl (uint32_t nr, target_ulong val) +void helper_store_ibatl(uint32_t nr, target_ulong val) { ppc_store_ibatl(env, nr, val); } -void helper_store_dbatu (uint32_t nr, target_ulong val) +void helper_store_dbatu(uint32_t nr, target_ulong val) { ppc_store_dbatu(env, nr, val); } -void helper_store_dbatl (uint32_t nr, target_ulong val) +void helper_store_dbatl(uint32_t nr, target_ulong val) { ppc_store_dbatl(env, nr, val); } -void helper_store_601_batl (uint32_t nr, target_ulong val) +void helper_store_601_batl(uint32_t nr, target_ulong val) { ppc_store_ibatl_601(env, nr, val); } -void helper_store_601_batu (uint32_t nr, target_ulong val) +void helper_store_601_batu(uint32_t nr, target_ulong val) { ppc_store_ibatu_601(env, nr, val); } @@ -254,48 +254,53 @@ void helper_store_601_batu (uint32_t nr, target_ulong val) static inline target_ulong addr_add(target_ulong addr, target_long arg) { #if defined(TARGET_PPC64) - if (!msr_sf) - return (uint32_t)(addr + arg); - else + if (!msr_sf) { + return (uint32_t)(addr + arg); + } else #endif - return addr + arg; -} - -void helper_lmw (target_ulong addr, uint32_t reg) -{ - for (; reg < 32; reg++) { - if (msr_le) - env->gpr[reg] = bswap32(ldl(addr)); - else - env->gpr[reg] = ldl(addr); - addr = addr_add(addr, 4); + { + return addr + arg; } } -void helper_stmw (target_ulong addr, uint32_t reg) +void helper_lmw(target_ulong addr, uint32_t reg) { for (; reg < 32; reg++) { - if (msr_le) + if (msr_le) { + env->gpr[reg] = bswap32(ldl(addr)); + } else { + env->gpr[reg] = ldl(addr); + } + addr = addr_add(addr, 4); + } +} + +void helper_stmw(target_ulong addr, uint32_t reg) +{ + for (; reg < 32; reg++) { + if (msr_le) { stl(addr, bswap32((uint32_t)env->gpr[reg])); - else + } else { stl(addr, (uint32_t)env->gpr[reg]); - addr = addr_add(addr, 4); + } + addr = addr_add(addr, 4); } } void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg) { int sh; + for (; nb > 3; nb -= 4) { env->gpr[reg] = ldl(addr); reg = (reg + 1) % 32; - addr = addr_add(addr, 4); + addr = addr_add(addr, 4); } if (unlikely(nb > 0)) { env->gpr[reg] = 0; for (sh = 24; nb > 0; nb--, sh -= 8) { env->gpr[reg] |= ldub(addr) << sh; - addr = addr_add(addr, 1); + addr = addr_add(addr, 1); } } } @@ -321,10 +326,11 @@ void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb) void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg) { int sh; + for (; nb > 3; nb -= 4) { stl(addr, env->gpr[reg]); reg = (reg + 1) % 32; - addr = addr_add(addr, 4); + addr = addr_add(addr, 4); } if (unlikely(nb > 0)) { for (sh = 24; nb > 0; nb--, sh -= 8) { @@ -336,13 +342,15 @@ void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg) static void do_dcbz(target_ulong addr, int dcache_line_size) { - addr &= ~(dcache_line_size - 1); int i; - for (i = 0 ; i < dcache_line_size ; i += 4) { - stl(addr + i , 0); + + addr &= ~(dcache_line_size - 1); + for (i = 0; i < dcache_line_size; i += 4) { + stl(addr + i, 0); } - if (env->reserve_addr == addr) + if (env->reserve_addr == addr) { env->reserve_addr = (target_ulong)-1ULL; + } } void helper_dcbz(target_ulong addr) @@ -352,10 +360,11 @@ void helper_dcbz(target_ulong addr) void helper_dcbz_970(target_ulong addr) { - if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) + if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) { do_dcbz(addr, 32); - else + } else { do_dcbz(addr, env->dcache_line_size); + } } void helper_icbi(target_ulong addr) @@ -369,20 +378,23 @@ void helper_icbi(target_ulong addr) ldl(addr); } -// XXX: to be tested -target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb) +/* XXX: to be tested */ +target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra, + uint32_t rb) { int i, c, d; + d = 24; for (i = 0; i < xer_bc; i++) { c = ldub(addr); - addr = addr_add(addr, 1); + addr = addr_add(addr, 1); /* ra (if not 0) and rb are never modified */ if (likely(reg != rb && (ra == 0 || reg != ra))) { env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d); } - if (unlikely(c == xer_cmp)) + if (unlikely(c == xer_cmp)) { break; + } if (likely(d != 0)) { d -= 8; } else { @@ -399,7 +411,7 @@ target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_ #if defined(TARGET_PPC64) /* multiply high word */ -uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2) +uint64_t helper_mulhd(uint64_t arg1, uint64_t arg2) { uint64_t tl, th; @@ -408,7 +420,7 @@ uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2) } /* multiply high word unsigned */ -uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2) +uint64_t helper_mulhdu(uint64_t arg1, uint64_t arg2) { uint64_t tl, th; @@ -416,7 +428,7 @@ uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2) return th; } -uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2) +uint64_t helper_mulldo(uint64_t arg1, uint64_t arg2) { int64_t th; uint64_t tl; @@ -432,20 +444,20 @@ uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2) } #endif -target_ulong helper_cntlzw (target_ulong t) +target_ulong helper_cntlzw(target_ulong t) { return clz32(t); } #if defined(TARGET_PPC64) -target_ulong helper_cntlzd (target_ulong t) +target_ulong helper_cntlzd(target_ulong t) { return clz64(t); } #endif /* shift right arithmetic helper */ -target_ulong helper_sraw (target_ulong value, target_ulong shift) +target_ulong helper_sraw(target_ulong value, target_ulong shift) { int32_t ret; @@ -474,7 +486,7 @@ target_ulong helper_sraw (target_ulong value, target_ulong shift) } #if defined(TARGET_PPC64) -target_ulong helper_srad (target_ulong value, target_ulong shift) +target_ulong helper_srad(target_ulong value, target_ulong shift) { int64_t ret; @@ -504,7 +516,7 @@ target_ulong helper_srad (target_ulong value, target_ulong shift) #endif #if defined(TARGET_PPC64) -target_ulong helper_popcntb (target_ulong val) +target_ulong helper_popcntb(target_ulong val) { val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL); @@ -515,7 +527,7 @@ target_ulong helper_popcntb (target_ulong val) return val; } -target_ulong helper_popcntw (target_ulong val) +target_ulong helper_popcntw(target_ulong val) { val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL); @@ -530,12 +542,12 @@ target_ulong helper_popcntw (target_ulong val) return val; } -target_ulong helper_popcntd (target_ulong val) +target_ulong helper_popcntd(target_ulong val) { return ctpop64(val); } #else -target_ulong helper_popcntb (target_ulong val) +target_ulong helper_popcntb(target_ulong val) { val = (val & 0x55555555) + ((val >> 1) & 0x55555555); val = (val & 0x33333333) + ((val >> 2) & 0x33333333); @@ -543,7 +555,7 @@ target_ulong helper_popcntb (target_ulong val) return val; } -target_ulong helper_popcntw (target_ulong val) +target_ulong helper_popcntw(target_ulong val) { val = (val & 0x55555555) + ((val >> 1) & 0x55555555); val = (val & 0x33333333) + ((val >> 2) & 0x33333333); @@ -560,6 +572,7 @@ uint64_t helper_float32_to_float64(uint32_t arg) { CPU_FloatU f; CPU_DoubleU d; + f.l = arg; d.d = float32_to_float64(f.f, &env->fp_status); return d.ll; @@ -569,6 +582,7 @@ uint32_t helper_float64_to_float32(uint64_t arg) { CPU_FloatU f; CPU_DoubleU d; + d.ll = arg; f.f = float64_to_float32(d.d, &env->fp_status); return f.l; @@ -583,11 +597,12 @@ static inline int isden(float64 d) return ((u.ll >> 52) & 0x7FF) == 0; } -uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf) +uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf) { CPU_DoubleU farg; int isneg; int ret; + farg.ll = arg; isneg = float64_is_neg(farg.d); if (unlikely(float64_is_any_nan(farg.d))) { @@ -600,17 +615,19 @@ uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf) } } else if (unlikely(float64_is_infinity(farg.d))) { /* +/- infinity */ - if (isneg) + if (isneg) { ret = 0x09; - else + } else { ret = 0x05; + } } else { if (float64_is_zero(farg.d)) { /* +/- zero */ - if (isneg) + if (isneg) { ret = 0x12; - else + } else { ret = 0x02; + } } else { if (isden(farg.d)) { /* Denormalized numbers */ @@ -645,10 +662,10 @@ static inline uint64_t fload_invalid_op_excp(int op) switch (op) { case POWERPC_EXCP_FP_VXSNAN: env->fpscr |= 1 << FPSCR_VXSNAN; - break; + break; case POWERPC_EXCP_FP_VXSOFT: env->fpscr |= 1 << FPSCR_VXSOFT; - break; + break; case POWERPC_EXCP_FP_VXISI: /* Magnitude subtraction of infinities */ env->fpscr |= 1 << FPSCR_VXISI; @@ -711,8 +728,10 @@ static inline uint64_t fload_invalid_op_excp(int op) if (ve != 0) { /* Update the floating-point enabled exception summary */ env->fpscr |= 1 << FPSCR_FEX; - if (msr_fe0 != 0 || msr_fe1 != 0) - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op); + if (msr_fe0 != 0 || msr_fe1 != 0) { + helper_raise_exception_err(POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_FP | op); + } } return ret; } @@ -807,7 +826,7 @@ static inline void fpscr_set_rounding_mode(void) set_float_rounding_mode(rnd_type, &env->fp_status); } -void helper_fpscr_clrbit (uint32_t bit) +void helper_fpscr_clrbit(uint32_t bit) { int prev; @@ -825,7 +844,7 @@ void helper_fpscr_clrbit (uint32_t bit) } } -void helper_fpscr_setbit (uint32_t bit) +void helper_fpscr_setbit(uint32_t bit) { int prev; @@ -835,27 +854,32 @@ void helper_fpscr_setbit (uint32_t bit) switch (bit) { case FPSCR_VX: env->fpscr |= 1 << FPSCR_FX; - if (fpscr_ve) + if (fpscr_ve) { goto raise_ve; + } case FPSCR_OX: env->fpscr |= 1 << FPSCR_FX; - if (fpscr_oe) + if (fpscr_oe) { goto raise_oe; + } break; case FPSCR_UX: env->fpscr |= 1 << FPSCR_FX; - if (fpscr_ue) + if (fpscr_ue) { goto raise_ue; + } break; case FPSCR_ZX: env->fpscr |= 1 << FPSCR_FX; - if (fpscr_ze) + if (fpscr_ze) { goto raise_ze; + } break; case FPSCR_XX: env->fpscr |= 1 << FPSCR_FX; - if (fpscr_xe) + if (fpscr_xe) { goto raise_xe; + } break; case FPSCR_VXSNAN: case FPSCR_VXISI: @@ -868,31 +892,41 @@ void helper_fpscr_setbit (uint32_t bit) case FPSCR_VXCVI: env->fpscr |= 1 << FPSCR_VX; env->fpscr |= 1 << FPSCR_FX; - if (fpscr_ve != 0) + if (fpscr_ve != 0) { goto raise_ve; + } break; case FPSCR_VE: if (fpscr_vx != 0) { raise_ve: env->error_code = POWERPC_EXCP_FP; - if (fpscr_vxsnan) + if (fpscr_vxsnan) { env->error_code |= POWERPC_EXCP_FP_VXSNAN; - if (fpscr_vxisi) + } + if (fpscr_vxisi) { env->error_code |= POWERPC_EXCP_FP_VXISI; - if (fpscr_vxidi) + } + if (fpscr_vxidi) { env->error_code |= POWERPC_EXCP_FP_VXIDI; - if (fpscr_vxzdz) + } + if (fpscr_vxzdz) { env->error_code |= POWERPC_EXCP_FP_VXZDZ; - if (fpscr_vximz) + } + if (fpscr_vximz) { env->error_code |= POWERPC_EXCP_FP_VXIMZ; - if (fpscr_vxvc) + } + if (fpscr_vxvc) { env->error_code |= POWERPC_EXCP_FP_VXVC; - if (fpscr_vxsoft) + } + if (fpscr_vxsoft) { env->error_code |= POWERPC_EXCP_FP_VXSOFT; - if (fpscr_vxsqrt) + } + if (fpscr_vxsqrt) { env->error_code |= POWERPC_EXCP_FP_VXSQRT; - if (fpscr_vxcvi) + } + if (fpscr_vxcvi) { env->error_code |= POWERPC_EXCP_FP_VXCVI; + } goto raise_excp; } break; @@ -933,14 +967,14 @@ void helper_fpscr_setbit (uint32_t bit) raise_excp: /* Update the floating-point enabled exception summary */ env->fpscr |= 1 << FPSCR_FEX; - /* We have to update Rc1 before raising the exception */ + /* We have to update Rc1 before raising the exception */ env->exception_index = POWERPC_EXCP_PROGRAM; break; } } } -void helper_store_fpscr (uint64_t arg, uint32_t mask) +void helper_store_fpscr(uint64_t arg, uint32_t mask) { /* * We use only the 32 LSB of the incoming fpr @@ -959,28 +993,30 @@ void helper_store_fpscr (uint64_t arg, uint32_t mask) } } /* Update VX and FEX */ - if (fpscr_ix != 0) + if (fpscr_ix != 0) { env->fpscr |= 1 << FPSCR_VX; - else + } else { env->fpscr &= ~(1 << FPSCR_VX); + } if ((fpscr_ex & fpscr_eex) != 0) { env->fpscr |= 1 << FPSCR_FEX; env->exception_index = POWERPC_EXCP_PROGRAM; /* XXX: we should compute it properly */ env->error_code = POWERPC_EXCP_FP; - } - else + } else { env->fpscr &= ~(1 << FPSCR_FEX); + } fpscr_set_rounding_mode(); } -void helper_float_check_status (void) +void helper_float_check_status(void) { if (env->exception_index == POWERPC_EXCP_PROGRAM && (env->error_code & POWERPC_EXCP_FP)) { /* Differred floating-point exception after target FPR update */ - if (msr_fe0 != 0 || msr_fe1 != 0) + if (msr_fe0 != 0 || msr_fe1 != 0) { helper_raise_exception_err(env->exception_index, env->error_code); + } } else { int status = get_float_exception_flags(&env->fp_status); if (status & float_flag_divbyzero) { @@ -995,13 +1031,13 @@ void helper_float_check_status (void) } } -void helper_reset_fpstatus (void) +void helper_reset_fpstatus(void) { set_float_exception_flags(0, &env->fp_status); } /* fadd - fadd. */ -uint64_t helper_fadd (uint64_t arg1, uint64_t arg2) +uint64_t helper_fadd(uint64_t arg1, uint64_t arg2) { CPU_DoubleU farg1, farg2; @@ -1025,7 +1061,7 @@ uint64_t helper_fadd (uint64_t arg1, uint64_t arg2) } /* fsub - fsub. */ -uint64_t helper_fsub (uint64_t arg1, uint64_t arg2) +uint64_t helper_fsub(uint64_t arg1, uint64_t arg2) { CPU_DoubleU farg1, farg2; @@ -1049,7 +1085,7 @@ uint64_t helper_fsub (uint64_t arg1, uint64_t arg2) } /* fmul - fmul. */ -uint64_t helper_fmul (uint64_t arg1, uint64_t arg2) +uint64_t helper_fmul(uint64_t arg1, uint64_t arg2) { CPU_DoubleU farg1, farg2; @@ -1073,14 +1109,15 @@ uint64_t helper_fmul (uint64_t arg1, uint64_t arg2) } /* fdiv - fdiv. */ -uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2) +uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2) { CPU_DoubleU farg1, farg2; farg1.ll = arg1; farg2.ll = arg2; - if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) { + if (unlikely(float64_is_infinity(farg1.d) && + float64_is_infinity(farg2.d))) { /* Division of infinity by infinity */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI); } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) { @@ -1099,7 +1136,7 @@ uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2) } /* fabs */ -uint64_t helper_fabs (uint64_t arg) +uint64_t helper_fabs(uint64_t arg) { CPU_DoubleU farg; @@ -1109,7 +1146,7 @@ uint64_t helper_fabs (uint64_t arg) } /* fnabs */ -uint64_t helper_fnabs (uint64_t arg) +uint64_t helper_fnabs(uint64_t arg) { CPU_DoubleU farg; @@ -1120,7 +1157,7 @@ uint64_t helper_fnabs (uint64_t arg) } /* fneg */ -uint64_t helper_fneg (uint64_t arg) +uint64_t helper_fneg(uint64_t arg) { CPU_DoubleU farg; @@ -1130,15 +1167,18 @@ uint64_t helper_fneg (uint64_t arg) } /* fctiw - fctiw. */ -uint64_t helper_fctiw (uint64_t arg) +uint64_t helper_fctiw(uint64_t arg) { CPU_DoubleU farg; + farg.ll = arg; if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_quiet_nan(farg.d) || + float64_is_infinity(farg.d))) { /* qNan / infinity conversion */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { @@ -1152,15 +1192,18 @@ uint64_t helper_fctiw (uint64_t arg) } /* fctiwz - fctiwz. */ -uint64_t helper_fctiwz (uint64_t arg) +uint64_t helper_fctiwz(uint64_t arg) { CPU_DoubleU farg; + farg.ll = arg; if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_quiet_nan(farg.d) || + float64_is_infinity(farg.d))) { /* qNan / infinity conversion */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { @@ -1175,23 +1218,27 @@ uint64_t helper_fctiwz (uint64_t arg) #if defined(TARGET_PPC64) /* fcfid - fcfid. */ -uint64_t helper_fcfid (uint64_t arg) +uint64_t helper_fcfid(uint64_t arg) { CPU_DoubleU farg; + farg.d = int64_to_float64(arg, &env->fp_status); return farg.ll; } /* fctid - fctid. */ -uint64_t helper_fctid (uint64_t arg) +uint64_t helper_fctid(uint64_t arg) { CPU_DoubleU farg; + farg.ll = arg; if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_quiet_nan(farg.d) || + float64_is_infinity(farg.d))) { /* qNan / infinity conversion */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { @@ -1201,15 +1248,18 @@ uint64_t helper_fctid (uint64_t arg) } /* fctidz - fctidz. */ -uint64_t helper_fctidz (uint64_t arg) +uint64_t helper_fctidz(uint64_t arg) { CPU_DoubleU farg; + farg.ll = arg; if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_quiet_nan(farg.d) || + float64_is_infinity(farg.d))) { /* qNan / infinity conversion */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { @@ -1223,12 +1273,15 @@ uint64_t helper_fctidz (uint64_t arg) static inline uint64_t do_fri(uint64_t arg, int rounding_mode) { CPU_DoubleU farg; + farg.ll = arg; if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN round */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_quiet_nan(farg.d) || + float64_is_infinity(farg.d))) { /* qNan / infinity round */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { @@ -1240,28 +1293,28 @@ static inline uint64_t do_fri(uint64_t arg, int rounding_mode) return farg.ll; } -uint64_t helper_frin (uint64_t arg) +uint64_t helper_frin(uint64_t arg) { return do_fri(arg, float_round_nearest_even); } -uint64_t helper_friz (uint64_t arg) +uint64_t helper_friz(uint64_t arg) { return do_fri(arg, float_round_to_zero); } -uint64_t helper_frip (uint64_t arg) +uint64_t helper_frip(uint64_t arg) { return do_fri(arg, float_round_up); } -uint64_t helper_frim (uint64_t arg) +uint64_t helper_frim(uint64_t arg) { return do_fri(arg, float_round_down); } /* fmadd - fmadd. */ -uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) +uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) { CPU_DoubleU farg1, farg2, farg3; @@ -1286,7 +1339,8 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) ft0_128 = float64_to_float128(farg1.d, &env->fp_status); ft1_128 = float64_to_float128(farg2.d, &env->fp_status); ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); - if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) && + if (unlikely(float128_is_infinity(ft0_128) && + float64_is_infinity(farg3.d) && float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { /* Magnitude subtraction of infinities */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); @@ -1301,7 +1355,7 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) } /* fmsub - fmsub. */ -uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) +uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) { CPU_DoubleU farg1, farg2, farg3; @@ -1310,7 +1364,8 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg3.ll = arg3; if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || - (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { + (float64_is_zero(farg1.d) && + float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); } else { @@ -1326,7 +1381,8 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) ft0_128 = float64_to_float128(farg1.d, &env->fp_status); ft1_128 = float64_to_float128(farg2.d, &env->fp_status); ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); - if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) && + if (unlikely(float128_is_infinity(ft0_128) && + float64_is_infinity(farg3.d) && float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { /* Magnitude subtraction of infinities */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); @@ -1340,7 +1396,7 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) } /* fnmadd - fnmadd. */ -uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) +uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) { CPU_DoubleU farg1, farg2, farg3; @@ -1365,7 +1421,8 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) ft0_128 = float64_to_float128(farg1.d, &env->fp_status); ft1_128 = float64_to_float128(farg2.d, &env->fp_status); ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); - if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) && + if (unlikely(float128_is_infinity(ft0_128) && + float64_is_infinity(farg3.d) && float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { /* Magnitude subtraction of infinities */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); @@ -1382,7 +1439,7 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) } /* fnmsub - fnmsub. */ -uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) +uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) { CPU_DoubleU farg1, farg2, farg3; @@ -1391,7 +1448,8 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg3.ll = arg3; if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || - (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { + (float64_is_zero(farg1.d) && + float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); } else { @@ -1407,7 +1465,8 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) ft0_128 = float64_to_float128(farg1.d, &env->fp_status); ft1_128 = float64_to_float128(farg2.d, &env->fp_status); ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); - if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) && + if (unlikely(float128_is_infinity(ft0_128) && + float64_is_infinity(farg3.d) && float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { /* Magnitude subtraction of infinities */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); @@ -1424,15 +1483,16 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) } /* frsp - frsp. */ -uint64_t helper_frsp (uint64_t arg) +uint64_t helper_frsp(uint64_t arg) { CPU_DoubleU farg; float32 f32; + farg.ll = arg; if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN square root */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } f32 = float64_to_float32(farg.d, &env->fp_status); farg.d = float32_to_float64(f32, &env->fp_status); @@ -1441,9 +1501,10 @@ uint64_t helper_frsp (uint64_t arg) } /* fsqrt - fsqrt. */ -uint64_t helper_fsqrt (uint64_t arg) +uint64_t helper_fsqrt(uint64_t arg) { CPU_DoubleU farg; + farg.ll = arg; if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { @@ -1460,9 +1521,10 @@ uint64_t helper_fsqrt (uint64_t arg) } /* fre - fre. */ -uint64_t helper_fre (uint64_t arg) +uint64_t helper_fre(uint64_t arg) { CPU_DoubleU farg; + farg.ll = arg; if (unlikely(float64_is_signaling_nan(farg.d))) { @@ -1474,10 +1536,11 @@ uint64_t helper_fre (uint64_t arg) } /* fres - fres. */ -uint64_t helper_fres (uint64_t arg) +uint64_t helper_fres(uint64_t arg) { CPU_DoubleU farg; float32 f32; + farg.ll = arg; if (unlikely(float64_is_signaling_nan(farg.d))) { @@ -1492,10 +1555,11 @@ uint64_t helper_fres (uint64_t arg) } /* frsqrte - frsqrte. */ -uint64_t helper_frsqrte (uint64_t arg) +uint64_t helper_frsqrte(uint64_t arg) { CPU_DoubleU farg; float32 f32; + farg.ll = arg; if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { @@ -1515,23 +1579,25 @@ uint64_t helper_frsqrte (uint64_t arg) } /* fsel - fsel. */ -uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3) +uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3) { CPU_DoubleU farg1; farg1.ll = arg1; - if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_any_nan(farg1.d)) { + if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && + !float64_is_any_nan(farg1.d)) { return arg2; } else { return arg3; } } -void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD) +void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD) { CPU_DoubleU farg1, farg2; uint32_t ret = 0; + farg1.ll = arg1; farg2.ll = arg2; @@ -1557,10 +1623,11 @@ void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD) } } -void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD) +void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD) { CPU_DoubleU farg1, farg2; uint32_t ret = 0; + farg1.ll = arg1; farg2.ll = arg2; @@ -1578,7 +1645,7 @@ void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD) env->fpscr &= ~(0x0F << FPSCR_FPRF); env->fpscr |= ret << FPSCR_FPRF; env->crf[crfD] = ret; - if (unlikely (ret == 0x01UL)) { + if (unlikely(ret == 0x01UL)) { if (float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d)) { /* sNaN comparison */ @@ -1591,8 +1658,8 @@ void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD) } } -#if !defined (CONFIG_USER_ONLY) -void helper_store_msr (target_ulong val) +#if !defined(CONFIG_USER_ONLY) +void helper_store_msr(target_ulong val) { val = hreg_store_msr(env, val, 0); if (val != 0) { @@ -1611,8 +1678,9 @@ static inline void do_rfi(target_ulong nip, target_ulong msr, } else { nip = (uint32_t)nip; msr = (uint32_t)(msr & msrm); - if (keep_msrh) + if (keep_msrh) { msr |= env->msr & ~((uint64_t)0xFFFFFFFF); + } } #else nip = (uint32_t)nip; @@ -1621,7 +1689,7 @@ static inline void do_rfi(target_ulong nip, target_ulong msr, /* XXX: beware: this is false if VLE is supported */ env->nip = nip & ~((target_ulong)0x00000003); hreg_store_msr(env, msr, 1); -#if defined (DEBUG_OP) +#if defined(DEBUG_OP) cpu_dump_rfi(env->nip, env->msr); #endif /* No need to raise an exception here, @@ -1630,20 +1698,20 @@ static inline void do_rfi(target_ulong nip, target_ulong msr, env->interrupt_request |= CPU_INTERRUPT_EXITTB; } -void helper_rfi (void) +void helper_rfi(void) { do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], ~((target_ulong)0x783F0000), 1); } #if defined(TARGET_PPC64) -void helper_rfid (void) +void helper_rfid(void) { do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], ~((target_ulong)0x783F0000), 0); } -void helper_hrfid (void) +void helper_hrfid(void) { do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1], ~((target_ulong)0x783F0000), 0); @@ -1651,7 +1719,7 @@ void helper_hrfid (void) #endif #endif -void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags) +void helper_tw(target_ulong arg1, target_ulong arg2, uint32_t flags) { if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) || @@ -1663,21 +1731,22 @@ void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags) } #if defined(TARGET_PPC64) -void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags) +void helper_td(target_ulong arg1, target_ulong arg2, uint32_t flags) { if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) || ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || - ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) + ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); + } } #endif /*****************************************************************************/ /* PowerPC 601 specific instructions (POWER bridge) */ -target_ulong helper_clcs (uint32_t arg) +target_ulong helper_clcs(uint32_t arg) { switch (arg) { case 0x0CUL: @@ -1691,12 +1760,12 @@ target_ulong helper_clcs (uint32_t arg) case 0x0EUL: /* Minimum cache line size */ return (env->icache_line_size < env->dcache_line_size) ? - env->icache_line_size : env->dcache_line_size; + env->icache_line_size : env->dcache_line_size; break; case 0x0FUL: /* Maximum cache line size */ return (env->icache_line_size > env->dcache_line_size) ? - env->icache_line_size : env->dcache_line_size; + env->icache_line_size : env->dcache_line_size; break; default: /* Undefined */ @@ -1705,7 +1774,7 @@ target_ulong helper_clcs (uint32_t arg) } } -target_ulong helper_div (target_ulong arg1, target_ulong arg2) +target_ulong helper_div(target_ulong arg1, target_ulong arg2) { uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ]; @@ -1719,7 +1788,7 @@ target_ulong helper_div (target_ulong arg1, target_ulong arg2) } } -target_ulong helper_divo (target_ulong arg1, target_ulong arg2) +target_ulong helper_divo(target_ulong arg1, target_ulong arg2) { uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ]; @@ -1731,7 +1800,7 @@ target_ulong helper_divo (target_ulong arg1, target_ulong arg2) } else { env->spr[SPR_MQ] = tmp % arg2; tmp /= (int32_t)arg2; - if ((int32_t)tmp != tmp) { + if ((int32_t)tmp != tmp) { env->xer |= (1 << XER_OV) | (1 << XER_SO); } else { env->xer &= ~(1 << XER_OV); @@ -1740,7 +1809,7 @@ target_ulong helper_divo (target_ulong arg1, target_ulong arg2) } } -target_ulong helper_divs (target_ulong arg1, target_ulong arg2) +target_ulong helper_divs(target_ulong arg1, target_ulong arg2) { if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || (int32_t)arg2 == 0) { @@ -1752,7 +1821,7 @@ target_ulong helper_divs (target_ulong arg1, target_ulong arg2) } } -target_ulong helper_divso (target_ulong arg1, target_ulong arg2) +target_ulong helper_divso(target_ulong arg1, target_ulong arg2) { if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || (int32_t)arg2 == 0) { @@ -1766,8 +1835,8 @@ target_ulong helper_divso (target_ulong arg1, target_ulong arg2) } } -#if !defined (CONFIG_USER_ONLY) -target_ulong helper_rac (target_ulong addr) +#if !defined(CONFIG_USER_ONLY) +target_ulong helper_rac(target_ulong addr) { mmu_ctx_t ctx; int nb_BATs; @@ -1779,13 +1848,14 @@ target_ulong helper_rac (target_ulong addr) /* XXX: FIX THIS: Pretend we have no BAT */ nb_BATs = env->nb_BATs; env->nb_BATs = 0; - if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) + if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) { ret = ctx.raddr; + } env->nb_BATs = nb_BATs; return ret; } -void helper_rfsvc (void) +void helper_rfsvc(void) { do_rfi(env->lr, env->ctr, 0x0000FFFF, 0); } @@ -1799,8 +1869,8 @@ void helper_rfsvc (void) * -arg / 256 * return 256 * log10(10 + 1.0) + 0.5 */ -#if !defined (CONFIG_USER_ONLY) -target_ulong helper_602_mfrom (target_ulong arg) +#if !defined(CONFIG_USER_ONLY) +target_ulong helper_602_mfrom(target_ulong arg) { if (likely(arg < 602)) { #include "mfrom_table.c" @@ -1815,15 +1885,17 @@ target_ulong helper_602_mfrom (target_ulong arg) /* Embedded PowerPC specific helpers */ /* XXX: to be improved to check access rights when in user-mode */ -target_ulong helper_load_dcr (target_ulong dcrn) +target_ulong helper_load_dcr(target_ulong dcrn) { uint32_t val = 0; if (unlikely(env->dcr_env == NULL)) { qemu_log("No DCR environment\n"); helper_raise_exception_err(POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL); - } else if (unlikely(ppc_dcr_read(env->dcr_env, (uint32_t)dcrn, &val) != 0)) { + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL); + } else if (unlikely(ppc_dcr_read(env->dcr_env, + (uint32_t)dcrn, &val) != 0)) { qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn); helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG); @@ -1831,13 +1903,15 @@ target_ulong helper_load_dcr (target_ulong dcrn) return val; } -void helper_store_dcr (target_ulong dcrn, target_ulong val) +void helper_store_dcr(target_ulong dcrn, target_ulong val) { if (unlikely(env->dcr_env == NULL)) { qemu_log("No DCR environment\n"); helper_raise_exception_err(POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL); - } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, (uint32_t)val) != 0)) { + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL); + } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, + (uint32_t)val) != 0)) { qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn); helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG); @@ -1845,25 +1919,25 @@ void helper_store_dcr (target_ulong dcrn, target_ulong val) } #if !defined(CONFIG_USER_ONLY) -void helper_40x_rfci (void) +void helper_40x_rfci(void) { do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3], ~((target_ulong)0xFFFF0000), 0); } -void helper_rfci (void) +void helper_rfci(void) { do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1, ~((target_ulong)0x3FFF0000), 0); } -void helper_rfdi (void) +void helper_rfdi(void) { do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1, ~((target_ulong)0x3FFF0000), 0); } -void helper_rfmci (void) +void helper_rfmci(void) { do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1, ~((target_ulong)0x3FFF0000), 0); @@ -1871,7 +1945,8 @@ void helper_rfmci (void) #endif /* 440 specific */ -target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc) +target_ulong helper_dlmzb(target_ulong high, target_ulong low, + uint32_t update_Rc) { target_ulong mask; int i; @@ -1917,57 +1992,59 @@ target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_ #endif #if defined(HOST_WORDS_BIGENDIAN) -#define VECTOR_FOR_INORDER_I(index, element) \ +#define VECTOR_FOR_INORDER_I(index, element) \ for (index = 0; index < ARRAY_SIZE(r->element); index++) #else -#define VECTOR_FOR_INORDER_I(index, element) \ - for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--) +#define VECTOR_FOR_INORDER_I(index, element) \ + for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--) #endif /* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise, * execute the following block. */ -#define DO_HANDLE_NAN(result, x) \ - if (float32_is_any_nan(x)) { \ - CPU_FloatU __f; \ - __f.f = x; \ - __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \ - result = __f.f; \ +#define DO_HANDLE_NAN(result, x) \ + if (float32_is_any_nan(x)) { \ + CPU_FloatU __f; \ + __f.f = x; \ + __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \ + result = __f.f; \ } else #define HANDLE_NAN1(result, x) \ DO_HANDLE_NAN(result, x) -#define HANDLE_NAN2(result, x, y) \ +#define HANDLE_NAN2(result, x, y) \ DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) -#define HANDLE_NAN3(result, x, y, z) \ +#define HANDLE_NAN3(result, x, y, z) \ DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z) /* Saturating arithmetic helpers. */ -#define SATCVT(from, to, from_type, to_type, min, max) \ - static inline to_type cvt##from##to(from_type x, int *sat) \ - { \ - to_type r; \ - if (x < (from_type)min) { \ - r = min; \ - *sat = 1; \ - } else if (x > (from_type)max) { \ - r = max; \ - *sat = 1; \ - } else { \ - r = x; \ - } \ - return r; \ +#define SATCVT(from, to, from_type, to_type, min, max) \ + static inline to_type cvt##from##to(from_type x, int *sat) \ + { \ + to_type r; \ + \ + if (x < (from_type)min) { \ + r = min; \ + *sat = 1; \ + } else if (x > (from_type)max) { \ + r = max; \ + *sat = 1; \ + } else { \ + r = x; \ + } \ + return r; \ } -#define SATCVTU(from, to, from_type, to_type, min, max) \ - static inline to_type cvt##from##to(from_type x, int *sat) \ - { \ - to_type r; \ - if (x > (from_type)max) { \ - r = max; \ - *sat = 1; \ - } else { \ - r = x; \ - } \ - return r; \ +#define SATCVTU(from, to, from_type, to_type, min, max) \ + static inline to_type cvt##from##to(from_type x, int *sat) \ + { \ + to_type r; \ + \ + if (x > (from_type)max) { \ + r = max; \ + *sat = 1; \ + } else { \ + r = x; \ + } \ + return r; \ } SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX) SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX) @@ -1983,17 +2060,20 @@ SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX) #undef SATCVTU #define LVE(name, access, swap, element) \ - void helper_##name (ppc_avr_t *r, target_ulong addr) \ + void helper_##name(ppc_avr_t *r, target_ulong addr) \ { \ size_t n_elems = ARRAY_SIZE(r->element); \ - int adjust = HI_IDX*(n_elems-1); \ + int adjust = HI_IDX*(n_elems - 1); \ int sh = sizeof(r->element[0]) >> 1; \ int index = (addr & 0xf) >> sh; \ - if(msr_le) { \ - r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \ - } else { \ - r->element[LO_IDX ? index : (adjust - index)] = access(addr); \ - } \ + \ + if (msr_le) { \ + r->element[LO_IDX ? index : (adjust - index)] = \ + swap(access(addr)); \ + } else { \ + r->element[LO_IDX ? index : (adjust - index)] = \ + access(addr); \ + } \ } #define I(x) (x) LVE(lvebx, ldub, I, u8) @@ -2002,32 +2082,33 @@ LVE(lvewx, ldl, bswap32, u32) #undef I #undef LVE -void helper_lvsl (ppc_avr_t *r, target_ulong sh) +void helper_lvsl(ppc_avr_t *r, target_ulong sh) { int i, j = (sh & 0xf); - VECTOR_FOR_INORDER_I (i, u8) { + VECTOR_FOR_INORDER_I(i, u8) { r->u8[i] = j++; } } -void helper_lvsr (ppc_avr_t *r, target_ulong sh) +void helper_lvsr(ppc_avr_t *r, target_ulong sh) { int i, j = 0x10 - (sh & 0xf); - VECTOR_FOR_INORDER_I (i, u8) { + VECTOR_FOR_INORDER_I(i, u8) { r->u8[i] = j++; } } -#define STVE(name, access, swap, element) \ - void helper_##name (ppc_avr_t *r, target_ulong addr) \ - { \ - size_t n_elems = ARRAY_SIZE(r->element); \ - int adjust = HI_IDX*(n_elems-1); \ - int sh = sizeof(r->element[0]) >> 1; \ - int index = (addr & 0xf) >> sh; \ - if(msr_le) { \ +#define STVE(name, access, swap, element) \ + void helper_##name(ppc_avr_t *r, target_ulong addr) \ + { \ + size_t n_elems = ARRAY_SIZE(r->element); \ + int adjust = HI_IDX * (n_elems - 1); \ + int sh = sizeof(r->element[0]) >> 1; \ + int index = (addr & 0xf) >> sh; \ + \ + if (msr_le) { \ access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \ } else { \ access(addr, r->element[LO_IDX ? index : (adjust - index)]); \ @@ -2040,7 +2121,7 @@ STVE(stvewx, stl, bswap32, u32) #undef I #undef LVE -void helper_mtvscr (ppc_avr_t *r) +void helper_mtvscr(ppc_avr_t *r) { #if defined(HOST_WORDS_BIGENDIAN) env->vscr = r->u32[3]; @@ -2050,25 +2131,27 @@ void helper_mtvscr (ppc_avr_t *r) set_flush_to_zero(vscr_nj, &env->vec_status); } -void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i; + for (i = 0; i < ARRAY_SIZE(r->u32); i++) { r->u32[i] = ~a->u32[i] < b->u32[i]; } } -#define VARITH_DO(name, op, element) \ -void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ -{ \ - int i; \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - r->element[i] = a->element[i] op b->element[i]; \ - } \ -} -#define VARITH(suffix, element) \ - VARITH_DO(add##suffix, +, element) \ - VARITH_DO(sub##suffix, -, element) +#define VARITH_DO(name, op, element) \ + void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + r->element[i] = a->element[i] op b->element[i]; \ + } \ + } +#define VARITH(suffix, element) \ + VARITH_DO(add##suffix, +, element) \ + VARITH_DO(sub##suffix, -, element) VARITH(ubm, u8) VARITH(uhm, u16) VARITH(uwm, u32) @@ -2076,9 +2159,10 @@ VARITH(uwm, u32) #undef VARITH #define VARITHFP(suffix, func) \ - void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \ r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \ @@ -2096,26 +2180,33 @@ VARITHFP(subfp, float32_sub) } #define VARITHSAT_DO(name, op, optype, cvt, element) \ - void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ int sat = 0; \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ switch (sizeof(r->element[0])) { \ - case 1: VARITHSAT_CASE(optype, op, cvt, element); break; \ - case 2: VARITHSAT_CASE(optype, op, cvt, element); break; \ - case 4: VARITHSAT_CASE(optype, op, cvt, element); break; \ + case 1: \ + VARITHSAT_CASE(optype, op, cvt, element); \ + break; \ + case 2: \ + VARITHSAT_CASE(optype, op, cvt, element); \ + break; \ + case 4: \ + VARITHSAT_CASE(optype, op, cvt, element); \ + break; \ } \ } \ if (sat) { \ env->vscr |= (1 << VSCR_SAT); \ } \ } -#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \ - VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \ +#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \ + VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \ VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element) -#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \ - VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \ +#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \ + VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \ VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element) VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb) VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh) @@ -2129,16 +2220,18 @@ VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw) #undef VARITHSAT_UNSIGNED #define VAVG_DO(name, element, etype) \ - void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \ r->element[i] = x >> 1; \ } \ } -#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \ +#define VAVG(type, signed_element, signed_type, unsigned_element, \ + unsigned_type) \ VAVG_DO(avgs##type, signed_element, signed_type) \ VAVG_DO(avgu##type, unsigned_element, unsigned_type) VAVG(b, s8, int16_t, u8, uint16_t) @@ -2148,12 +2241,13 @@ VAVG(w, s32, int64_t, u32, uint64_t) #undef VAVG #define VCF(suffix, cvt, element) \ - void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \ + void helper_vcf##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \ { \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ float32 t = cvt(b->element[i], &env->vec_status); \ - r->f[i] = float32_scalbn (t, -uim, &env->vec_status); \ + r->f[i] = float32_scalbn(t, -uim, &env->vec_status); \ } \ } VCF(ux, uint32_to_float32, u32) @@ -2161,18 +2255,26 @@ VCF(sx, int32_to_float32, s32) #undef VCF #define VCMP_DO(suffix, compare, element, record) \ - void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ uint32_t ones = (uint32_t)-1; \ uint32_t all = ones; \ uint32_t none = 0; \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \ - switch (sizeof (a->element[0])) { \ - case 4: r->u32[i] = result; break; \ - case 2: r->u16[i] = result; break; \ - case 1: r->u8[i] = result; break; \ + uint32_t result = (a->element[i] compare b->element[i] ? \ + ones : 0x0); \ + switch (sizeof(a->element[0])) { \ + case 4: \ + r->u32[i] = result; \ + break; \ + case 2: \ + r->u16[i] = result; \ + break; \ + case 1: \ + r->u8[i] = result; \ + break; \ } \ all &= result; \ none |= result; \ @@ -2197,15 +2299,17 @@ VCMP(gtsw, >, s32) #undef VCMP #define VCMPFP_DO(suffix, compare, order, record) \ - void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ uint32_t ones = (uint32_t)-1; \ uint32_t all = ones; \ uint32_t none = 0; \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ uint32_t result; \ - int rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); \ + int rel = float32_compare_quiet(a->f[i], b->f[i], \ + &env->vec_status); \ if (rel == float_relation_unordered) { \ result = 0; \ } else if (rel compare order) { \ @@ -2221,8 +2325,8 @@ VCMP(gtsw, >, s32) env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \ } \ } -#define VCMPFP(suffix, compare, order) \ - VCMPFP_DO(suffix, compare, order, 0) \ +#define VCMPFP(suffix, compare, order) \ + VCMPFP_DO(suffix, compare, order, 0) \ VCMPFP_DO(suffix##_dot, compare, order, 1) VCMPFP(eqfp, ==, float_relation_equal) VCMPFP(gefp, !=, float_relation_less) @@ -2235,6 +2339,7 @@ static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, { int i; int all_in = 0; + for (i = 0; i < ARRAY_SIZE(r->f); i++) { int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); if (le_rel == float_relation_unordered) { @@ -2245,6 +2350,7 @@ static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status); int le = le_rel != float_relation_greater; int ge = ge_rel != float_relation_less; + r->u32[i] = ((!le) << 31) | ((!ge) << 30); all_in |= (!le | !ge); } @@ -2254,22 +2360,23 @@ static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, } } -void helper_vcmpbfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vcmpbfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { vcmpbfp_internal(r, a, b, 0); } -void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vcmpbfp_dot(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { vcmpbfp_internal(r, a, b, 1); } #define VCT(suffix, satcvt, element) \ - void helper_vct##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \ + void helper_vct##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \ { \ int i; \ int sat = 0; \ float_status s = env->vec_status; \ + \ set_float_rounding_mode(float_round_to_zero, &s); \ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ if (float32_is_any_nan(b->f[i])) { \ @@ -2277,6 +2384,7 @@ void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } else { \ float64 t = float32_to_float64(b->f[i], &s); \ int64_t j; \ + \ t = float64_scalbn(t, uim, &s); \ j = float64_to_int64(t, &s); \ r->element[i] = satcvt(j, &sat); \ @@ -2290,14 +2398,16 @@ VCT(uxs, cvtsduw, u32) VCT(sxs, cvtsdsw, s32) #undef VCT -void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmaddfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int i; + for (i = 0; i < ARRAY_SIZE(r->f); i++) { HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) { /* Need to do the computation in higher precision and round * once at the end. */ float64 af, bf, cf, t; + af = float32_to_float64(a->f[i], &env->vec_status); bf = float32_to_float64(b->f[i], &env->vec_status); cf = float32_to_float64(c->f[i], &env->vec_status); @@ -2308,7 +2418,7 @@ void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmhaddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int sat = 0; int i; @@ -2316,7 +2426,8 @@ void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) for (i = 0; i < ARRAY_SIZE(r->s16); i++) { int32_t prod = a->s16[i] * b->s16[i]; int32_t t = (int32_t)c->s16[i] + (prod >> 15); - r->s16[i] = cvtswsh (t, &sat); + + r->s16[i] = cvtswsh(t, &sat); } if (sat) { @@ -2324,7 +2435,7 @@ void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmhraddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int sat = 0; int i; @@ -2332,7 +2443,7 @@ void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) for (i = 0; i < ARRAY_SIZE(r->s16); i++) { int32_t prod = a->s16[i] * b->s16[i] + 0x00004000; int32_t t = (int32_t)c->s16[i] + (prod >> 15); - r->s16[i] = cvtswsh (t, &sat); + r->s16[i] = cvtswsh(t, &sat); } if (sat) { @@ -2341,9 +2452,10 @@ void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } #define VMINMAX_DO(name, compare, element) \ - void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ if (a->element[i] compare b->element[i]) { \ r->element[i] = b->element[i]; \ @@ -2353,8 +2465,8 @@ void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } \ } #define VMINMAX(suffix, element) \ - VMINMAX_DO(min##suffix, >, element) \ - VMINMAX_DO(max##suffix, <, element) + VMINMAX_DO(min##suffix, >, element) \ + VMINMAX_DO(max##suffix, <, element) VMINMAX(sb, s8) VMINMAX(sh, s16) VMINMAX(sw, s32) @@ -2365,12 +2477,14 @@ VMINMAX(uw, u32) #undef VMINMAX #define VMINMAXFP(suffix, rT, rF) \ - void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \ - if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \ + if (float32_lt_quiet(a->f[i], b->f[i], \ + &env->vec_status)) { \ r->f[i] = rT->f[i]; \ } else { \ r->f[i] = rF->f[i]; \ @@ -2382,9 +2496,10 @@ VMINMAXFP(minfp, a, b) VMINMAXFP(maxfp, b, a) #undef VMINMAXFP -void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int i; + for (i = 0; i < ARRAY_SIZE(r->s16); i++) { int32_t prod = a->s16[i] * b->s16[i]; r->s16[i] = (int16_t) (prod + c->s16[i]); @@ -2392,18 +2507,21 @@ void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } #define VMRG_DO(name, element, highp) \ - void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ ppc_avr_t result; \ int i; \ size_t n_elems = ARRAY_SIZE(r->element); \ - for (i = 0; i < n_elems/2; i++) { \ + \ + for (i = 0; i < n_elems / 2; i++) { \ if (highp) { \ result.element[i*2+HI_IDX] = a->element[i]; \ result.element[i*2+LO_IDX] = b->element[i]; \ } else { \ - result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \ - result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \ + result.element[n_elems - i * 2 - (1 + HI_IDX)] = \ + b->element[n_elems - i - 1]; \ + result.element[n_elems - i * 2 - (1 + LO_IDX)] = \ + a->element[n_elems - i - 1]; \ } \ } \ *r = result; \ @@ -2416,8 +2534,8 @@ void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) #define MRGLO 0 #endif #define VMRG(suffix, element) \ - VMRG_DO(mrgl##suffix, element, MRGHI) \ - VMRG_DO(mrgh##suffix, element, MRGLO) + VMRG_DO(mrgl##suffix, element, MRGHI) \ + VMRG_DO(mrgh##suffix, element, MRGLO) VMRG(b, u8) VMRG(h, u16) VMRG(w, u32) @@ -2426,7 +2544,7 @@ VMRG(w, u32) #undef MRGHI #undef MRGLO -void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmsummbm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int32_t prod[16]; int i; @@ -2436,11 +2554,12 @@ void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } VECTOR_FOR_INORDER_I(i, s32) { - r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3]; + r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] + + prod[4 * i + 2] + prod[4 * i + 3]; } } -void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmsumshm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int32_t prod[8]; int i; @@ -2450,11 +2569,11 @@ void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } VECTOR_FOR_INORDER_I(i, s32) { - r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1]; + r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1]; } } -void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmsumshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int32_t prod[8]; int i; @@ -2464,8 +2583,9 @@ void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) prod[i] = (int32_t)a->s16[i] * b->s16[i]; } - VECTOR_FOR_INORDER_I (i, s32) { - int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1]; + VECTOR_FOR_INORDER_I(i, s32) { + int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1]; + r->u32[i] = cvtsdsw(t, &sat); } @@ -2474,7 +2594,7 @@ void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmsumubm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { uint16_t prod[16]; int i; @@ -2484,11 +2604,12 @@ void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } VECTOR_FOR_INORDER_I(i, u32) { - r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3]; + r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] + + prod[4 * i + 2] + prod[4 * i + 3]; } } -void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmsumuhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { uint32_t prod[8]; int i; @@ -2498,11 +2619,11 @@ void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } VECTOR_FOR_INORDER_I(i, u32) { - r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1]; + r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1]; } } -void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmsumuhs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { uint32_t prod[8]; int i; @@ -2512,8 +2633,9 @@ void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) prod[i] = a->u16[i] * b->u16[i]; } - VECTOR_FOR_INORDER_I (i, s32) { - uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1]; + VECTOR_FOR_INORDER_I(i, s32) { + uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1]; + r->u32[i] = cvtuduw(t, &sat); } @@ -2523,20 +2645,23 @@ void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } #define VMUL_DO(name, mul_element, prod_element, evenp) \ - void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ int i; \ + \ VECTOR_FOR_INORDER_I(i, prod_element) { \ if (evenp) { \ - r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \ + r->prod_element[i] = a->mul_element[i * 2 + HI_IDX] * \ + b->mul_element[i * 2 + HI_IDX]; \ } else { \ - r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \ + r->prod_element[i] = a->mul_element[i * 2 + LO_IDX] * \ + b->mul_element[i * 2 + LO_IDX]; \ } \ } \ } -#define VMUL(suffix, mul_element, prod_element) \ - VMUL_DO(mule##suffix, mul_element, prod_element, 1) \ - VMUL_DO(mulo##suffix, mul_element, prod_element, 0) +#define VMUL(suffix, mul_element, prod_element) \ + VMUL_DO(mule##suffix, mul_element, prod_element, 1) \ + VMUL_DO(mulo##suffix, mul_element, prod_element, 0) VMUL(sb, s8, s16) VMUL(sh, s16, s32) VMUL(ub, u8, u16) @@ -2544,14 +2669,16 @@ VMUL(uh, u16, u32) #undef VMUL_DO #undef VMUL -void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vnmsubfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int i; + for (i = 0; i < ARRAY_SIZE(r->f); i++) { HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) { /* Need to do the computation is higher precision and round * once at the end. */ float64 af, bf, cf, t; + af = float32_to_float64(a->f[i], &env->vec_status); bf = float32_to_float64(b->f[i], &env->vec_status); cf = float32_to_float64(c->f[i], &env->vec_status); @@ -2563,17 +2690,19 @@ void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vperm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { ppc_avr_t result; int i; - VECTOR_FOR_INORDER_I (i, u8) { + + VECTOR_FOR_INORDER_I(i, u8) { int s = c->u8[i] & 0x1f; #if defined(HOST_WORDS_BIGENDIAN) int index = s & 0xf; #else int index = 15 - (s & 0xf); #endif + if (s & 0x10) { result.u8[i] = b->u8[index]; } else { @@ -2588,7 +2717,7 @@ void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) #else #define PKBIG 0 #endif -void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i, j; ppc_avr_t result; @@ -2598,9 +2727,10 @@ void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) const ppc_avr_t *x[2] = { b, a }; #endif - VECTOR_FOR_INORDER_I (i, u64) { - VECTOR_FOR_INORDER_I (j, u32){ + VECTOR_FOR_INORDER_I(i, u64) { + VECTOR_FOR_INORDER_I(j, u32) { uint32_t e = x[i]->u32[j]; + result.u16[4*i+j] = (((e >> 9) & 0xfc00) | ((e >> 6) & 0x3e0) | ((e >> 3) & 0x1f)); @@ -2609,15 +2739,16 @@ void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) *r = result; } -#define VPK(suffix, from, to, cvt, dosat) \ - void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ +#define VPK(suffix, from, to, cvt, dosat) \ + void helper_vpk##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ int i; \ int sat = 0; \ ppc_avr_t result; \ ppc_avr_t *a0 = PKBIG ? a : b; \ ppc_avr_t *a1 = PKBIG ? b : a; \ - VECTOR_FOR_INORDER_I (i, from) { \ + \ + VECTOR_FOR_INORDER_I(i, from) { \ result.to[i] = cvt(a0->from[i], &sat); \ result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \ } \ @@ -2639,9 +2770,10 @@ VPK(uwum, u32, u16, I, 0) #undef VPK #undef PKBIG -void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b) +void helper_vrefp(ppc_avr_t *r, ppc_avr_t *b) { int i; + for (i = 0; i < ARRAY_SIZE(r->f); i++) { HANDLE_NAN1(r->f[i], b->f[i]) { r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status); @@ -2649,17 +2781,18 @@ void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b) } } -#define VRFI(suffix, rounding) \ - void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b) \ - { \ - int i; \ - float_status s = env->vec_status; \ - set_float_rounding_mode(rounding, &s); \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - HANDLE_NAN1(r->f[i], b->f[i]) { \ - r->f[i] = float32_round_to_int (b->f[i], &s); \ - } \ - } \ +#define VRFI(suffix, rounding) \ + void helper_vrfi##suffix(ppc_avr_t *r, ppc_avr_t *b) \ + { \ + int i; \ + float_status s = env->vec_status; \ + \ + set_float_rounding_mode(rounding, &s); \ + for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ + HANDLE_NAN1(r->f[i], b->f[i]) { \ + r->f[i] = float32_round_to_int (b->f[i], &s); \ + } \ + } \ } VRFI(n, float_round_nearest_even) VRFI(m, float_round_down) @@ -2668,13 +2801,17 @@ VRFI(z, float_round_to_zero) #undef VRFI #define VROTATE(suffix, element) \ - void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \ + unsigned int mask = ((1 << \ + (3 + (sizeof(a->element[0]) >> 1))) \ + - 1); \ unsigned int shift = b->element[i] & mask; \ - r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \ + r->element[i] = (a->element[i] << shift) | \ + (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \ } \ } VROTATE(b, u8) @@ -2682,26 +2819,29 @@ VROTATE(h, u16) VROTATE(w, u32) #undef VROTATE -void helper_vrsqrtefp (ppc_avr_t *r, ppc_avr_t *b) +void helper_vrsqrtefp(ppc_avr_t *r, ppc_avr_t *b) { int i; + for (i = 0; i < ARRAY_SIZE(r->f); i++) { HANDLE_NAN1(r->f[i], b->f[i]) { float32 t = float32_sqrt(b->f[i], &env->vec_status); + r->f[i] = float32_div(float32_one, t, &env->vec_status); } } } -void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vsel(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]); r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]); } -void helper_vexptefp (ppc_avr_t *r, ppc_avr_t *b) +void helper_vexptefp(ppc_avr_t *r, ppc_avr_t *b) { int i; + for (i = 0; i < ARRAY_SIZE(r->f); i++) { HANDLE_NAN1(r->f[i], b->f[i]) { r->f[i] = float32_exp2(b->f[i], &env->vec_status); @@ -2709,9 +2849,10 @@ void helper_vexptefp (ppc_avr_t *r, ppc_avr_t *b) } } -void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b) +void helper_vlogefp(ppc_avr_t *r, ppc_avr_t *b) { int i; + for (i = 0; i < ARRAY_SIZE(r->f); i++) { HANDLE_NAN1(r->f[i], b->f[i]) { r->f[i] = float32_log2(b->f[i], &env->vec_status); @@ -2730,11 +2871,12 @@ void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b) * shift counts are not identical. We check to make sure that they are * to conform to what real hardware appears to do. */ #define VSHIFT(suffix, leftp) \ - void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ int shift = b->u8[LO_IDX*15] & 0x7; \ int doit = 1; \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \ doit = doit && ((b->u8[i] & 0x7) == shift); \ } \ @@ -2743,10 +2885,12 @@ void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b) *r = *a; \ } else if (leftp) { \ uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \ + \ r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \ r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \ } else { \ uint64_t carry = a->u64[HI_IDX] << (64 - shift); \ + \ r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \ r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \ } \ @@ -2759,12 +2903,16 @@ VSHIFT(r, RIGHT) #undef RIGHT #define VSL(suffix, element) \ - void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \ + unsigned int mask = ((1 << \ + (3 + (sizeof(a->element[0]) >> 1))) \ + - 1); \ unsigned int shift = b->element[i] & mask; \ + \ r->element[i] = a->element[i] << shift; \ } \ } @@ -2773,7 +2921,7 @@ VSL(h, u16) VSL(w, u32) #undef VSL -void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift) +void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift) { int sh = shift & 0xf; int i; @@ -2783,7 +2931,7 @@ void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift) for (i = 0; i < ARRAY_SIZE(r->u8); i++) { int index = sh + i; if (index > 0xf) { - result.u8[i] = b->u8[index-0x10]; + result.u8[i] = b->u8[index - 0x10]; } else { result.u8[i] = a->u8[index]; } @@ -2792,7 +2940,7 @@ void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift) for (i = 0; i < ARRAY_SIZE(r->u8); i++) { int index = (16 - sh) + i; if (index > 0xf) { - result.u8[i] = a->u8[index-0x10]; + result.u8[i] = a->u8[index - 0x10]; } else { result.u8[i] = b->u8[index]; } @@ -2801,16 +2949,16 @@ void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift) *r = result; } -void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { - int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf; + int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf; -#if defined (HOST_WORDS_BIGENDIAN) - memmove (&r->u8[0], &a->u8[sh], 16-sh); - memset (&r->u8[16-sh], 0, sh); +#if defined(HOST_WORDS_BIGENDIAN) + memmove(&r->u8[0], &a->u8[sh], 16 - sh); + memset(&r->u8[16-sh], 0, sh); #else - memmove (&r->u8[sh], &a->u8[0], 16-sh); - memset (&r->u8[0], 0, sh); + memmove(&r->u8[sh], &a->u8[0], 16 - sh); + memset(&r->u8[0], 0, sh); #endif } @@ -2819,13 +2967,15 @@ void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) #if defined(HOST_WORDS_BIGENDIAN) #define SPLAT_ELEMENT(element) _SPLAT_MASKED(element) #else -#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element)) +#define SPLAT_ELEMENT(element) \ + (ARRAY_SIZE(r->element) - 1 - _SPLAT_MASKED(element)) #endif #define VSPLT(suffix, element) \ - void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \ + void helper_vsplt##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \ { \ uint32_t s = b->element[SPLAT_ELEMENT(element)]; \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ r->element[i] = s; \ } \ @@ -2838,10 +2988,11 @@ VSPLT(w, u32) #undef _SPLAT_MASKED #define VSPLTI(suffix, element, splat_type) \ - void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \ + void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \ { \ splat_type x = (int8_t)(splat << 3) >> 3; \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ r->element[i] = x; \ } \ @@ -2852,12 +3003,16 @@ VSPLTI(w, s32, int32_t) #undef VSPLTI #define VSR(suffix, element) \ - void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_vsr##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ int i; \ + \ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \ + unsigned int mask = ((1 << \ + (3 + (sizeof(a->element[0]) >> 1))) \ + - 1); \ unsigned int shift = b->element[i] & mask; \ + \ r->element[i] = a->element[i] >> shift; \ } \ } @@ -2869,28 +3024,29 @@ VSR(h, u16) VSR(w, u32) #undef VSR -void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { - int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf; + int sh = (b->u8[LO_IDX * 0xf] >> 3) & 0xf; -#if defined (HOST_WORDS_BIGENDIAN) - memmove (&r->u8[sh], &a->u8[0], 16-sh); - memset (&r->u8[0], 0, sh); +#if defined(HOST_WORDS_BIGENDIAN) + memmove(&r->u8[sh], &a->u8[0], 16 - sh); + memset(&r->u8[0], 0, sh); #else - memmove (&r->u8[0], &a->u8[sh], 16-sh); - memset (&r->u8[16-sh], 0, sh); + memmove(&r->u8[0], &a->u8[sh], 16 - sh); + memset(&r->u8[16 - sh], 0, sh); #endif } -void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i; + for (i = 0; i < ARRAY_SIZE(r->u32); i++) { r->u32[i] = a->u32[i] >= b->u32[i]; } } -void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vsumsws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int64_t t; int i, upper; @@ -2915,7 +3071,7 @@ void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } } -void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vsum2sws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i, j, upper; ppc_avr_t result; @@ -2927,12 +3083,13 @@ void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) upper = 0; #endif for (i = 0; i < ARRAY_SIZE(r->u64); i++) { - int64_t t = (int64_t)b->s32[upper+i*2]; + int64_t t = (int64_t)b->s32[upper + i * 2]; + result.u64[i] = 0; for (j = 0; j < ARRAY_SIZE(r->u64); j++) { - t += a->s32[2*i+j]; + t += a->s32[2 * i + j]; } - result.s32[upper+i*2] = cvtsdsw(t, &sat); + result.s32[upper + i * 2] = cvtsdsw(t, &sat); } *r = result; @@ -2941,15 +3098,16 @@ void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } } -void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vsum4sbs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i, j; int sat = 0; for (i = 0; i < ARRAY_SIZE(r->s32); i++) { int64_t t = (int64_t)b->s32[i]; + for (j = 0; j < ARRAY_SIZE(r->s32); j++) { - t += a->s8[4*i+j]; + t += a->s8[4 * i + j]; } r->s32[i] = cvtsdsw(t, &sat); } @@ -2959,14 +3117,15 @@ void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } } -void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vsum4shs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int sat = 0; int i; for (i = 0; i < ARRAY_SIZE(r->s32); i++) { int64_t t = (int64_t)b->s32[i]; - t += a->s16[2*i] + a->s16[2*i+1]; + + t += a->s16[2 * i] + a->s16[2 * i + 1]; r->s32[i] = cvtsdsw(t, &sat); } @@ -2975,15 +3134,16 @@ void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } } -void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vsum4ubs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i, j; int sat = 0; for (i = 0; i < ARRAY_SIZE(r->u32); i++) { uint64_t t = (uint64_t)b->u32[i]; + for (j = 0; j < ARRAY_SIZE(r->u32); j++) { - t += a->u8[4*i+j]; + t += a->u8[4 * i + j]; } r->u32[i] = cvtuduw(t, &sat); } @@ -3000,17 +3160,19 @@ void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) #define UPKHI 0 #define UPKLO 1 #endif -#define VUPKPX(suffix, hi) \ - void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \ - { \ - int i; \ - ppc_avr_t result; \ - for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \ - uint16_t e = b->u16[hi ? i : i+4]; \ - uint8_t a = (e >> 15) ? 0xff : 0; \ - uint8_t r = (e >> 10) & 0x1f; \ - uint8_t g = (e >> 5) & 0x1f; \ - uint8_t b = e & 0x1f; \ +#define VUPKPX(suffix, hi) \ + void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \ + { \ + int i; \ + ppc_avr_t result; \ + \ + for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \ + uint16_t e = b->u16[hi ? i : i+4]; \ + uint8_t a = (e >> 15) ? 0xff : 0; \ + uint8_t r = (e >> 10) & 0x1f; \ + uint8_t g = (e >> 5) & 0x1f; \ + uint8_t b = e & 0x1f; \ + \ result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \ } \ *r = result; \ @@ -3020,17 +3182,19 @@ VUPKPX(hpx, UPKHI) #undef VUPKPX #define VUPK(suffix, unpacked, packee, hi) \ - void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \ + void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \ { \ int i; \ ppc_avr_t result; \ + \ if (hi) { \ for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \ result.unpacked[i] = b->packee[i]; \ } \ } else { \ - for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \ - result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \ + for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \ + i++) { \ + result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \ } \ } \ *r = result; \ @@ -3070,8 +3234,8 @@ static inline uint32_t word_reverse(uint32_t val) (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24); } -#define MASKBITS 16 // Random value - to be fixed (implementation dependent) -target_ulong helper_brinc (target_ulong arg1, target_ulong arg2) +#define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */ +target_ulong helper_brinc(target_ulong arg1, target_ulong arg2) { uint32_t a, b, d, mask; @@ -3082,15 +3246,16 @@ target_ulong helper_brinc (target_ulong arg1, target_ulong arg2) return (arg1 & ~mask) | (d & b); } -uint32_t helper_cntlsw32 (uint32_t val) +uint32_t helper_cntlsw32(uint32_t val) { - if (val & 0x80000000) + if (val & 0x80000000) { return clz32(~val); - else + } else { return clz32(val); + } } -uint32_t helper_cntlzw32 (uint32_t val) +uint32_t helper_cntlzw32(uint32_t val) { return clz32(val); } @@ -3120,8 +3285,9 @@ static inline int32_t efsctsi(uint32_t val) u.l = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_quiet_nan(u.f))) + if (unlikely(float32_is_quiet_nan(u.f))) { return 0; + } return float32_to_int32(u.f, &env->vec_status); } @@ -3132,8 +3298,9 @@ static inline uint32_t efsctui(uint32_t val) u.l = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_quiet_nan(u.f))) + if (unlikely(float32_is_quiet_nan(u.f))) { return 0; + } return float32_to_uint32(u.f, &env->vec_status); } @@ -3144,8 +3311,9 @@ static inline uint32_t efsctsiz(uint32_t val) u.l = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_quiet_nan(u.f))) + if (unlikely(float32_is_quiet_nan(u.f))) { return 0; + } return float32_to_int32_round_to_zero(u.f, &env->vec_status); } @@ -3156,8 +3324,9 @@ static inline uint32_t efsctuiz(uint32_t val) u.l = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_quiet_nan(u.f))) + if (unlikely(float32_is_quiet_nan(u.f))) { return 0; + } return float32_to_uint32_round_to_zero(u.f, &env->vec_status); } @@ -3193,8 +3362,9 @@ static inline uint32_t efsctsf(uint32_t val) u.l = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_quiet_nan(u.f))) + if (unlikely(float32_is_quiet_nan(u.f))) { return 0; + } tmp = uint64_to_float32(1ULL << 32, &env->vec_status); u.f = float32_mul(u.f, tmp, &env->vec_status); @@ -3208,19 +3378,20 @@ static inline uint32_t efsctuf(uint32_t val) u.l = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_quiet_nan(u.f))) + if (unlikely(float32_is_quiet_nan(u.f))) { return 0; + } tmp = uint64_to_float32(1ULL << 32, &env->vec_status); u.f = float32_mul(u.f, tmp, &env->vec_status); return float32_to_uint32(u.f, &env->vec_status); } -#define HELPER_SPE_SINGLE_CONV(name) \ -uint32_t helper_e##name (uint32_t val) \ -{ \ - return e##name(val); \ -} +#define HELPER_SPE_SINGLE_CONV(name) \ + uint32_t helper_e##name(uint32_t val) \ + { \ + return e##name(val); \ + } /* efscfsi */ HELPER_SPE_SINGLE_CONV(fscfsi); /* efscfui */ @@ -3242,12 +3413,12 @@ HELPER_SPE_SINGLE_CONV(fsctsf); /* efsctuf */ HELPER_SPE_SINGLE_CONV(fsctuf); -#define HELPER_SPE_VECTOR_CONV(name) \ -uint64_t helper_ev##name (uint64_t val) \ -{ \ - return ((uint64_t)e##name(val >> 32) << 32) | \ - (uint64_t)e##name(val); \ -} +#define HELPER_SPE_VECTOR_CONV(name) \ + uint64_t helper_ev##name(uint64_t val) \ + { \ + return ((uint64_t)e##name(val >> 32) << 32) | \ + (uint64_t)e##name(val); \ + } /* evfscfsi */ HELPER_SPE_VECTOR_CONV(fscfsi); /* evfscfui */ @@ -3273,6 +3444,7 @@ HELPER_SPE_VECTOR_CONV(fsctuf); static inline uint32_t efsadd(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; + u1.l = op1; u2.l = op2; u1.f = float32_add(u1.f, u2.f, &env->vec_status); @@ -3282,6 +3454,7 @@ static inline uint32_t efsadd(uint32_t op1, uint32_t op2) static inline uint32_t efssub(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; + u1.l = op1; u2.l = op2; u1.f = float32_sub(u1.f, u2.f, &env->vec_status); @@ -3291,6 +3464,7 @@ static inline uint32_t efssub(uint32_t op1, uint32_t op2) static inline uint32_t efsmul(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; + u1.l = op1; u2.l = op2; u1.f = float32_mul(u1.f, u2.f, &env->vec_status); @@ -3300,17 +3474,18 @@ static inline uint32_t efsmul(uint32_t op1, uint32_t op2) static inline uint32_t efsdiv(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; + u1.l = op1; u2.l = op2; u1.f = float32_div(u1.f, u2.f, &env->vec_status); return u1.l; } -#define HELPER_SPE_SINGLE_ARITH(name) \ -uint32_t helper_e##name (uint32_t op1, uint32_t op2) \ -{ \ - return e##name(op1, op2); \ -} +#define HELPER_SPE_SINGLE_ARITH(name) \ + uint32_t helper_e##name(uint32_t op1, uint32_t op2) \ + { \ + return e##name(op1, op2); \ + } /* efsadd */ HELPER_SPE_SINGLE_ARITH(fsadd); /* efssub */ @@ -3320,12 +3495,12 @@ HELPER_SPE_SINGLE_ARITH(fsmul); /* efsdiv */ HELPER_SPE_SINGLE_ARITH(fsdiv); -#define HELPER_SPE_VECTOR_ARITH(name) \ -uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \ -{ \ - return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \ - (uint64_t)e##name(op1, op2); \ -} +#define HELPER_SPE_VECTOR_ARITH(name) \ + uint64_t helper_ev##name(uint64_t op1, uint64_t op2) \ + { \ + return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \ + (uint64_t)e##name(op1, op2); \ + } /* evfsadd */ HELPER_SPE_VECTOR_ARITH(fsadd); /* evfssub */ @@ -3339,6 +3514,7 @@ HELPER_SPE_VECTOR_ARITH(fsdiv); static inline uint32_t efscmplt(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; + u1.l = op1; u2.l = op2; return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0; @@ -3347,6 +3523,7 @@ static inline uint32_t efscmplt(uint32_t op1, uint32_t op2) static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; + u1.l = op1; u2.l = op2; return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4; @@ -3355,6 +3532,7 @@ static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2) static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; + u1.l = op1; u2.l = op2; return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0; @@ -3378,11 +3556,11 @@ static inline uint32_t efststeq(uint32_t op1, uint32_t op2) return efscmpeq(op1, op2); } -#define HELPER_SINGLE_SPE_CMP(name) \ -uint32_t helper_e##name (uint32_t op1, uint32_t op2) \ -{ \ - return e##name(op1, op2) << 2; \ -} +#define HELPER_SINGLE_SPE_CMP(name) \ + uint32_t helper_e##name(uint32_t op1, uint32_t op2) \ + { \ + return e##name(op1, op2) << 2; \ + } /* efststlt */ HELPER_SINGLE_SPE_CMP(fststlt); /* efststgt */ @@ -3401,11 +3579,11 @@ static inline uint32_t evcmp_merge(int t0, int t1) return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1); } -#define HELPER_VECTOR_SPE_CMP(name) \ -uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \ -{ \ - return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \ -} +#define HELPER_VECTOR_SPE_CMP(name) \ + uint32_t helper_ev##name(uint64_t op1, uint64_t op2) \ + { \ + return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \ + } /* evfststlt */ HELPER_VECTOR_SPE_CMP(fststlt); /* evfststgt */ @@ -3420,7 +3598,7 @@ HELPER_VECTOR_SPE_CMP(fscmpgt); HELPER_VECTOR_SPE_CMP(fscmpeq); /* Double-precision floating-point conversion */ -uint64_t helper_efdcfsi (uint32_t val) +uint64_t helper_efdcfsi(uint32_t val) { CPU_DoubleU u; @@ -3429,7 +3607,7 @@ uint64_t helper_efdcfsi (uint32_t val) return u.ll; } -uint64_t helper_efdcfsid (uint64_t val) +uint64_t helper_efdcfsid(uint64_t val) { CPU_DoubleU u; @@ -3438,7 +3616,7 @@ uint64_t helper_efdcfsid (uint64_t val) return u.ll; } -uint64_t helper_efdcfui (uint32_t val) +uint64_t helper_efdcfui(uint32_t val) { CPU_DoubleU u; @@ -3447,7 +3625,7 @@ uint64_t helper_efdcfui (uint32_t val) return u.ll; } -uint64_t helper_efdcfuid (uint64_t val) +uint64_t helper_efdcfuid(uint64_t val) { CPU_DoubleU u; @@ -3456,7 +3634,7 @@ uint64_t helper_efdcfuid (uint64_t val) return u.ll; } -uint32_t helper_efdctsi (uint64_t val) +uint32_t helper_efdctsi(uint64_t val) { CPU_DoubleU u; @@ -3469,7 +3647,7 @@ uint32_t helper_efdctsi (uint64_t val) return float64_to_int32(u.d, &env->vec_status); } -uint32_t helper_efdctui (uint64_t val) +uint32_t helper_efdctui(uint64_t val) { CPU_DoubleU u; @@ -3482,7 +3660,7 @@ uint32_t helper_efdctui (uint64_t val) return float64_to_uint32(u.d, &env->vec_status); } -uint32_t helper_efdctsiz (uint64_t val) +uint32_t helper_efdctsiz(uint64_t val) { CPU_DoubleU u; @@ -3495,7 +3673,7 @@ uint32_t helper_efdctsiz (uint64_t val) return float64_to_int32_round_to_zero(u.d, &env->vec_status); } -uint64_t helper_efdctsidz (uint64_t val) +uint64_t helper_efdctsidz(uint64_t val) { CPU_DoubleU u; @@ -3508,7 +3686,7 @@ uint64_t helper_efdctsidz (uint64_t val) return float64_to_int64_round_to_zero(u.d, &env->vec_status); } -uint32_t helper_efdctuiz (uint64_t val) +uint32_t helper_efdctuiz(uint64_t val) { CPU_DoubleU u; @@ -3521,7 +3699,7 @@ uint32_t helper_efdctuiz (uint64_t val) return float64_to_uint32_round_to_zero(u.d, &env->vec_status); } -uint64_t helper_efdctuidz (uint64_t val) +uint64_t helper_efdctuidz(uint64_t val) { CPU_DoubleU u; @@ -3534,7 +3712,7 @@ uint64_t helper_efdctuidz (uint64_t val) return float64_to_uint64_round_to_zero(u.d, &env->vec_status); } -uint64_t helper_efdcfsf (uint32_t val) +uint64_t helper_efdcfsf(uint32_t val) { CPU_DoubleU u; float64 tmp; @@ -3546,7 +3724,7 @@ uint64_t helper_efdcfsf (uint32_t val) return u.ll; } -uint64_t helper_efdcfuf (uint32_t val) +uint64_t helper_efdcfuf(uint32_t val) { CPU_DoubleU u; float64 tmp; @@ -3558,7 +3736,7 @@ uint64_t helper_efdcfuf (uint32_t val) return u.ll; } -uint32_t helper_efdctsf (uint64_t val) +uint32_t helper_efdctsf(uint64_t val) { CPU_DoubleU u; float64 tmp; @@ -3574,7 +3752,7 @@ uint32_t helper_efdctsf (uint64_t val) return float64_to_int32(u.d, &env->vec_status); } -uint32_t helper_efdctuf (uint64_t val) +uint32_t helper_efdctuf(uint64_t val) { CPU_DoubleU u; float64 tmp; @@ -3590,7 +3768,7 @@ uint32_t helper_efdctuf (uint64_t val) return float64_to_uint32(u.d, &env->vec_status); } -uint32_t helper_efscfd (uint64_t val) +uint32_t helper_efscfd(uint64_t val) { CPU_DoubleU u1; CPU_FloatU u2; @@ -3601,7 +3779,7 @@ uint32_t helper_efscfd (uint64_t val) return u2.l; } -uint64_t helper_efdcfs (uint32_t val) +uint64_t helper_efdcfs(uint32_t val) { CPU_DoubleU u2; CPU_FloatU u1; @@ -3613,36 +3791,40 @@ uint64_t helper_efdcfs (uint32_t val) } /* Double precision fixed-point arithmetic */ -uint64_t helper_efdadd (uint64_t op1, uint64_t op2) +uint64_t helper_efdadd(uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; + u1.ll = op1; u2.ll = op2; u1.d = float64_add(u1.d, u2.d, &env->vec_status); return u1.ll; } -uint64_t helper_efdsub (uint64_t op1, uint64_t op2) +uint64_t helper_efdsub(uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; + u1.ll = op1; u2.ll = op2; u1.d = float64_sub(u1.d, u2.d, &env->vec_status); return u1.ll; } -uint64_t helper_efdmul (uint64_t op1, uint64_t op2) +uint64_t helper_efdmul(uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; + u1.ll = op1; u2.ll = op2; u1.d = float64_mul(u1.d, u2.d, &env->vec_status); return u1.ll; } -uint64_t helper_efddiv (uint64_t op1, uint64_t op2) +uint64_t helper_efddiv(uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; + u1.ll = op1; u2.ll = op2; u1.d = float64_div(u1.d, u2.d, &env->vec_status); @@ -3650,43 +3832,46 @@ uint64_t helper_efddiv (uint64_t op1, uint64_t op2) } /* Double precision floating point helpers */ -uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2) +uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; + u1.ll = op1; u2.ll = op2; return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0; } -uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2) +uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; + u1.ll = op1; u2.ll = op2; return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4; } -uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2) +uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; + u1.ll = op1; u2.ll = op2; return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0; } -uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2) +uint32_t helper_efdcmplt(uint64_t op1, uint64_t op2) { /* XXX: TODO: test special values (NaN, infinites, ...) */ return helper_efdtstlt(op1, op2); } -uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2) +uint32_t helper_efdcmpgt(uint64_t op1, uint64_t op2) { /* XXX: TODO: test special values (NaN, infinites, ...) */ return helper_efdtstgt(op1, op2); } -uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2) +uint32_t helper_efdcmpeq(uint64_t op1, uint64_t op2) { /* XXX: TODO: test special values (NaN, infinites, ...) */ return helper_efdtsteq(op1, op2); @@ -3694,7 +3879,7 @@ uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2) /*****************************************************************************/ /* Softmmu support */ -#if !defined (CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu @@ -3740,30 +3925,31 @@ void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx, } /* Segment registers load and store */ -target_ulong helper_load_sr (target_ulong sr_num) +target_ulong helper_load_sr(target_ulong sr_num) { #if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) + if (env->mmu_model & POWERPC_MMU_64) { return ppc_load_sr(env, sr_num); + } #endif return env->sr[sr_num]; } -void helper_store_sr (target_ulong sr_num, target_ulong val) +void helper_store_sr(target_ulong sr_num, target_ulong val) { ppc_store_sr(env, sr_num, val); } /* SLB management */ #if defined(TARGET_PPC64) -void helper_store_slb (target_ulong rb, target_ulong rs) +void helper_store_slb(target_ulong rb, target_ulong rs) { if (ppc_store_slb(env, rb, rs) < 0) { helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL); } } -target_ulong helper_load_slb_esid (target_ulong rb) +target_ulong helper_load_slb_esid(target_ulong rb) { target_ulong rt; @@ -3773,7 +3959,7 @@ target_ulong helper_load_slb_esid (target_ulong rb) return rt; } -target_ulong helper_load_slb_vsid (target_ulong rb) +target_ulong helper_load_slb_vsid(target_ulong rb) { target_ulong rt; @@ -3783,12 +3969,12 @@ target_ulong helper_load_slb_vsid (target_ulong rb) return rt; } -void helper_slbia (void) +void helper_slbia(void) { ppc_slb_invalidate_all(env); } -void helper_slbie (target_ulong addr) +void helper_slbie(target_ulong addr) { ppc_slb_invalidate_one(env, addr); } @@ -3796,19 +3982,19 @@ void helper_slbie (target_ulong addr) #endif /* defined(TARGET_PPC64) */ /* TLB management */ -void helper_tlbia (void) +void helper_tlbia(void) { ppc_tlb_invalidate_all(env); } -void helper_tlbie (target_ulong addr) +void helper_tlbie(target_ulong addr) { ppc_tlb_invalidate_one(env, addr); } /* Software driven TLBs management */ /* PowerPC 602/603 software TLB load instructions helpers */ -static void do_6xx_tlb (target_ulong new_EPN, int is_code) +static void do_6xx_tlb(target_ulong new_EPN, int is_code) { target_ulong RPN, CMP, EPN; int way; @@ -3831,18 +4017,18 @@ static void do_6xx_tlb (target_ulong new_EPN, int is_code) way, is_code, CMP, RPN); } -void helper_6xx_tlbd (target_ulong EPN) +void helper_6xx_tlbd(target_ulong EPN) { do_6xx_tlb(EPN, 0); } -void helper_6xx_tlbi (target_ulong EPN) +void helper_6xx_tlbi(target_ulong EPN) { do_6xx_tlb(EPN, 1); } /* PowerPC 74xx software TLB load instructions helpers */ -static void do_74xx_tlb (target_ulong new_EPN, int is_code) +static void do_74xx_tlb(target_ulong new_EPN, int is_code) { target_ulong RPN, CMP, EPN; int way; @@ -3860,12 +4046,12 @@ static void do_74xx_tlb (target_ulong new_EPN, int is_code) way, is_code, CMP, RPN); } -void helper_74xx_tlbd (target_ulong EPN) +void helper_74xx_tlbd(target_ulong EPN) { do_74xx_tlb(EPN, 0); } -void helper_74xx_tlbi (target_ulong EPN) +void helper_74xx_tlbi(target_ulong EPN) { do_74xx_tlb(EPN, 1); } @@ -3913,7 +4099,7 @@ static inline int booke_page_size_to_tlb(target_ulong page_size) case 0x40000000UL: size = 0xA; break; -#if defined (TARGET_PPC64) +#if defined(TARGET_PPC64) case 0x000100000000ULL: size = 0xB; break; @@ -3954,7 +4140,7 @@ static inline int booke_page_size_to_tlb(target_ulong page_size) #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00 -target_ulong helper_4xx_tlbre_hi (target_ulong entry) +target_ulong helper_4xx_tlbre_hi(target_ulong entry) { ppcemb_tlb_t *tlb; target_ulong ret; @@ -3975,7 +4161,7 @@ target_ulong helper_4xx_tlbre_hi (target_ulong entry) return ret; } -target_ulong helper_4xx_tlbre_lo (target_ulong entry) +target_ulong helper_4xx_tlbre_lo(target_ulong entry) { ppcemb_tlb_t *tlb; target_ulong ret; @@ -3992,7 +4178,7 @@ target_ulong helper_4xx_tlbre_lo (target_ulong entry) return ret; } -void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val) +void helper_4xx_tlbwe_hi(target_ulong entry, target_ulong val) { ppcemb_tlb_t *tlb; target_ulong page, end; @@ -4051,7 +4237,7 @@ void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val) } } -void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val) +void helper_4xx_tlbwe_lo(target_ulong entry, target_ulong val) { ppcemb_tlb_t *tlb; @@ -4077,13 +4263,13 @@ void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val) tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); } -target_ulong helper_4xx_tlbsx (target_ulong address) +target_ulong helper_4xx_tlbsx(target_ulong address) { return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]); } /* PowerPC 440 TLB management */ -void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value) +void helper_440_tlbwe(uint32_t word, target_ulong entry, target_ulong value) { ppcemb_tlb_t *tlb; target_ulong EPN, RPN, size; @@ -4099,12 +4285,14 @@ void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value) /* Just here to please gcc */ case 0: EPN = value & 0xFFFFFC00; - if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) + if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) { do_flush_tlbs = 1; + } tlb->EPN = EPN; size = booke_tlb_to_page_size((value >> 4) & 0xF); - if ((tlb->prot & PAGE_VALID) && tlb->size < size) + if ((tlb->prot & PAGE_VALID) && tlb->size < size) { do_flush_tlbs = 1; + } tlb->size = size; tlb->attr &= ~0x1; tlb->attr |= (value >> 8) & 1; @@ -4117,35 +4305,43 @@ void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value) } } tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF; - if (do_flush_tlbs) + if (do_flush_tlbs) { tlb_flush(env, 1); + } break; case 1: RPN = value & 0xFFFFFC0F; - if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) + if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) { tlb_flush(env, 1); + } tlb->RPN = RPN; break; case 2: tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00); tlb->prot = tlb->prot & PAGE_VALID; - if (value & 0x1) + if (value & 0x1) { tlb->prot |= PAGE_READ << 4; - if (value & 0x2) + } + if (value & 0x2) { tlb->prot |= PAGE_WRITE << 4; - if (value & 0x4) + } + if (value & 0x4) { tlb->prot |= PAGE_EXEC << 4; - if (value & 0x8) + } + if (value & 0x8) { tlb->prot |= PAGE_READ; - if (value & 0x10) + } + if (value & 0x10) { tlb->prot |= PAGE_WRITE; - if (value & 0x20) + } + if (value & 0x20) { tlb->prot |= PAGE_EXEC; + } break; } } -target_ulong helper_440_tlbre (uint32_t word, target_ulong entry) +target_ulong helper_440_tlbre(uint32_t word, target_ulong entry) { ppcemb_tlb_t *tlb; target_ulong ret; @@ -4159,13 +4355,16 @@ target_ulong helper_440_tlbre (uint32_t word, target_ulong entry) case 0: ret = tlb->EPN; size = booke_page_size_to_tlb(tlb->size); - if (size < 0 || size > 0xF) + if (size < 0 || size > 0xF) { size = 1; + } ret |= size << 4; - if (tlb->attr & 0x1) + if (tlb->attr & 0x1) { ret |= 0x100; - if (tlb->prot & PAGE_VALID) + } + if (tlb->prot & PAGE_VALID) { ret |= 0x200; + } env->spr[SPR_440_MMUCR] &= ~0x000000FF; env->spr[SPR_440_MMUCR] |= tlb->PID; break; @@ -4174,24 +4373,30 @@ target_ulong helper_440_tlbre (uint32_t word, target_ulong entry) break; case 2: ret = tlb->attr & ~0x1; - if (tlb->prot & (PAGE_READ << 4)) + if (tlb->prot & (PAGE_READ << 4)) { ret |= 0x1; - if (tlb->prot & (PAGE_WRITE << 4)) + } + if (tlb->prot & (PAGE_WRITE << 4)) { ret |= 0x2; - if (tlb->prot & (PAGE_EXEC << 4)) + } + if (tlb->prot & (PAGE_EXEC << 4)) { ret |= 0x4; - if (tlb->prot & PAGE_READ) + } + if (tlb->prot & PAGE_READ) { ret |= 0x8; - if (tlb->prot & PAGE_WRITE) + } + if (tlb->prot & PAGE_WRITE) { ret |= 0x10; - if (tlb->prot & PAGE_EXEC) + } + if (tlb->prot & PAGE_EXEC) { ret |= 0x20; + } break; } return ret; } -target_ulong helper_440_tlbsx (target_ulong address) +target_ulong helper_440_tlbsx(target_ulong address) { return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF); } @@ -4247,7 +4452,7 @@ void helper_booke206_tlbwe(void) } if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) && - !msr_gs) { + !msr_gs) { /* XXX we don't support direct LRAT setting yet */ fprintf(stderr, "cpu: don't support LRAT setting yet\n"); return; @@ -4278,7 +4483,7 @@ void helper_booke206_tlbwe(void) cpu_abort(env, "missing HV implementation\n"); } tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) | - env->spr[SPR_BOOKE_MAS3]; + env->spr[SPR_BOOKE_MAS3]; tlb->mas1 = env->spr[SPR_BOOKE_MAS1]; /* MAV 1.0 only */ @@ -4376,7 +4581,7 @@ void helper_booke206_tlbsx(target_ulong address) } env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16) - << MAS1_TID_SHIFT; + << MAS1_TID_SHIFT; /* next victim logic */ env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT; From ad71ed68117c2a740f82ab297581d7dd8fa21aef Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:22 +0000 Subject: [PATCH 02/72] ppc: Split exception helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move exception helpers from op_helper.c to excp_helper.c. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 2 + target-ppc/excp_helper.c | 218 +++++++++++++++++++++++++++++++++++++++ target-ppc/op_helper.c | 190 ---------------------------------- 3 files changed, 220 insertions(+), 190 deletions(-) create mode 100644 target-ppc/excp_helper.c diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index f78161004e..c0f7e76d35 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -2,5 +2,7 @@ obj-y += translate.o op_helper.o helper.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o obj-y += op_helper.o helper.o +obj-y += excp_helper.o +$(obj)/excp_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c new file mode 100644 index 0000000000..f03f7384cf --- /dev/null +++ b/target-ppc/excp_helper.c @@ -0,0 +1,218 @@ +/* + * PowerPC exception emulation 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, see . + */ +#include "cpu.h" +#include "dyngen-exec.h" +#include "helper.h" + +#include "helper_regs.h" + +//#define DEBUG_OP +//#define DEBUG_EXCEPTIONS + +/*****************************************************************************/ +/* Exceptions processing helpers */ + +void helper_raise_exception_err(uint32_t exception, uint32_t error_code) +{ +#if 0 + printf("Raise exception %3x code : %d\n", exception, error_code); +#endif + env->exception_index = exception; + env->error_code = error_code; + cpu_loop_exit(env); +} + +void helper_raise_exception(uint32_t exception) +{ + helper_raise_exception_err(exception, 0); +} + +#if !defined(CONFIG_USER_ONLY) +void helper_store_msr(target_ulong val) +{ + val = hreg_store_msr(env, val, 0); + if (val != 0) { + env->interrupt_request |= CPU_INTERRUPT_EXITTB; + helper_raise_exception(val); + } +} + +static inline void do_rfi(target_ulong nip, target_ulong msr, + target_ulong msrm, int keep_msrh) +{ +#if defined(TARGET_PPC64) + if (msr & (1ULL << MSR_SF)) { + nip = (uint64_t)nip; + msr &= (uint64_t)msrm; + } else { + nip = (uint32_t)nip; + msr = (uint32_t)(msr & msrm); + if (keep_msrh) { + msr |= env->msr & ~((uint64_t)0xFFFFFFFF); + } + } +#else + 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, 1); +#if defined(DEBUG_OP) + 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 helper_rfi(void) +{ + do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0x783F0000), 1); +} + +#if defined(TARGET_PPC64) +void helper_rfid(void) +{ + do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0x783F0000), 0); +} + +void helper_hrfid(void) +{ + do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1], + ~((target_ulong)0x783F0000), 0); +} +#endif + +/*****************************************************************************/ +/* Embedded PowerPC specific helpers */ +void helper_40x_rfci(void) +{ + do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3], + ~((target_ulong)0xFFFF0000), 0); +} + +void helper_rfci(void) +{ + do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1, + ~((target_ulong)0x3FFF0000), 0); +} + +void helper_rfdi(void) +{ + do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1, + ~((target_ulong)0x3FFF0000), 0); +} + +void helper_rfmci(void) +{ + do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1, + ~((target_ulong)0x3FFF0000), 0); +} +#endif + +void helper_tw(target_ulong arg1, target_ulong arg2, uint32_t flags) +{ + if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || + ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) || + ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || + ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || + ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { + helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); + } +} + +#if defined(TARGET_PPC64) +void helper_td(target_ulong arg1, target_ulong arg2, uint32_t flags) +{ + if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || + ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) || + ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || + ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || + ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { + helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); + } +} +#endif + +#if !defined(CONFIG_USER_ONLY) +/*****************************************************************************/ +/* PowerPC 601 specific instructions (POWER bridge) */ + +void helper_rfsvc(void) +{ + do_rfi(env->lr, env->ctr, 0x0000FFFF, 0); +} + +/* Embedded.Processor Control */ +static int dbell2irq(target_ulong rb) +{ + int msg = rb & DBELL_TYPE_MASK; + int irq = -1; + + switch (msg) { + case DBELL_TYPE_DBELL: + irq = PPC_INTERRUPT_DOORBELL; + break; + case DBELL_TYPE_DBELL_CRIT: + irq = PPC_INTERRUPT_CDOORBELL; + break; + case DBELL_TYPE_G_DBELL: + case DBELL_TYPE_G_DBELL_CRIT: + case DBELL_TYPE_G_DBELL_MC: + /* XXX implement */ + default: + break; + } + + return irq; +} + +void helper_msgclr(target_ulong rb) +{ + int irq = dbell2irq(rb); + + if (irq < 0) { + return; + } + + env->pending_interrupts &= ~(1 << irq); +} + +void helper_msgsnd(target_ulong rb) +{ + int irq = dbell2irq(rb); + int pir = rb & DBELL_PIRTAG_MASK; + CPUPPCState *cenv; + + if (irq < 0) { + return; + } + + for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { + if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { + cenv->pending_interrupts |= 1 << irq; + cpu_interrupt(cenv, CPU_INTERRUPT_HARD); + } + } +} +#endif diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index d9f7a8beda..2e8786071a 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -29,7 +29,6 @@ #endif /* !defined(CONFIG_USER_ONLY) */ //#define DEBUG_OP -//#define DEBUG_EXCEPTIONS //#define DEBUG_SOFTWARE_TLB #ifdef DEBUG_SOFTWARE_TLB @@ -38,25 +37,6 @@ # define LOG_SWTLB(...) do { } while (0) #endif - -/*****************************************************************************/ -/* Exceptions processing helpers */ - -void helper_raise_exception_err(uint32_t exception, uint32_t error_code) -{ -#if 0 - printf("Raise exception %3x code : %d\n", exception, error_code); -#endif - env->exception_index = exception; - env->error_code = error_code; - cpu_loop_exit(env); -} - -void helper_raise_exception(uint32_t exception) -{ - helper_raise_exception_err(exception, 0); -} - /*****************************************************************************/ /* SPR accesses */ void helper_load_dump_spr(uint32_t sprn) @@ -1658,91 +1638,6 @@ void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD) } } -#if !defined(CONFIG_USER_ONLY) -void helper_store_msr(target_ulong val) -{ - val = hreg_store_msr(env, val, 0); - if (val != 0) { - env->interrupt_request |= CPU_INTERRUPT_EXITTB; - helper_raise_exception(val); - } -} - -static inline void do_rfi(target_ulong nip, target_ulong msr, - target_ulong msrm, int keep_msrh) -{ -#if defined(TARGET_PPC64) - if (msr & (1ULL << MSR_SF)) { - nip = (uint64_t)nip; - msr &= (uint64_t)msrm; - } else { - nip = (uint32_t)nip; - msr = (uint32_t)(msr & msrm); - if (keep_msrh) { - msr |= env->msr & ~((uint64_t)0xFFFFFFFF); - } - } -#else - 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, 1); -#if defined(DEBUG_OP) - 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 helper_rfi(void) -{ - do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], - ~((target_ulong)0x783F0000), 1); -} - -#if defined(TARGET_PPC64) -void helper_rfid(void) -{ - do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], - ~((target_ulong)0x783F0000), 0); -} - -void helper_hrfid(void) -{ - do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1], - ~((target_ulong)0x783F0000), 0); -} -#endif -#endif - -void helper_tw(target_ulong arg1, target_ulong arg2, uint32_t flags) -{ - if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || - ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) || - ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || - ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || - ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); - } -} - -#if defined(TARGET_PPC64) -void helper_td(target_ulong arg1, target_ulong arg2, uint32_t flags) -{ - if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || - ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) || - ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || - ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || - ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); - } -} -#endif - /*****************************************************************************/ /* PowerPC 601 specific instructions (POWER bridge) */ @@ -1854,11 +1749,6 @@ target_ulong helper_rac(target_ulong addr) env->nb_BATs = nb_BATs; return ret; } - -void helper_rfsvc(void) -{ - do_rfi(env->lr, env->ctr, 0x0000FFFF, 0); -} #endif /*****************************************************************************/ @@ -1918,32 +1808,6 @@ void helper_store_dcr(target_ulong dcrn, target_ulong val) } } -#if !defined(CONFIG_USER_ONLY) -void helper_40x_rfci(void) -{ - do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3], - ~((target_ulong)0xFFFF0000), 0); -} - -void helper_rfci(void) -{ - do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1, - ~((target_ulong)0x3FFF0000), 0); -} - -void helper_rfdi(void) -{ - do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1, - ~((target_ulong)0x3FFF0000), 0); -} - -void helper_rfmci(void) -{ - do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1, - ~((target_ulong)0x3FFF0000), 0); -} -#endif - /* 440 specific */ target_ulong helper_dlmzb(target_ulong high, target_ulong low, uint32_t update_Rc) @@ -4716,58 +4580,4 @@ void helper_booke206_tlbflush(uint32_t type) booke206_flush_tlb(env, flags, 1); } - -/* Embedded.Processor Control */ -static int dbell2irq(target_ulong rb) -{ - int msg = rb & DBELL_TYPE_MASK; - int irq = -1; - - switch (msg) { - case DBELL_TYPE_DBELL: - irq = PPC_INTERRUPT_DOORBELL; - break; - case DBELL_TYPE_DBELL_CRIT: - irq = PPC_INTERRUPT_CDOORBELL; - break; - case DBELL_TYPE_G_DBELL: - case DBELL_TYPE_G_DBELL_CRIT: - case DBELL_TYPE_G_DBELL_MC: - /* XXX implement */ - default: - break; - } - - return irq; -} - -void helper_msgclr(target_ulong rb) -{ - int irq = dbell2irq(rb); - - if (irq < 0) { - return; - } - - env->pending_interrupts &= ~(1 << irq); -} - -void helper_msgsnd(target_ulong rb) -{ - int irq = dbell2irq(rb); - int pir = rb & DBELL_PIRTAG_MASK; - CPUPPCState *cenv; - - if (irq < 0) { - return; - } - - for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { - if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { - cenv->pending_interrupts |= 1 << irq; - cpu_interrupt(cenv, CPU_INTERRUPT_HARD); - } - } -} - #endif /* !CONFIG_USER_ONLY */ From e5f17ac633fa7ac7a0936846c505a3c2d2b5687c Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:23 +0000 Subject: [PATCH 03/72] ppc: Avoid AREG0 for exception helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an explicit CPUPPCState parameter instead of relying on AREG0. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 1 - target-ppc/excp_helper.c | 60 +++++++++++++++++++++------------------- target-ppc/helper.h | 28 +++++++++---------- target-ppc/op_helper.c | 32 +++++++++++---------- target-ppc/translate.c | 40 ++++++++++++++------------- 5 files changed, 85 insertions(+), 76 deletions(-) diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index c0f7e76d35..a02b7bccde 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -4,5 +4,4 @@ obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o obj-y += op_helper.o helper.o obj-y += excp_helper.o -$(obj)/excp_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index f03f7384cf..c153f4ac92 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -17,7 +17,6 @@ * License along with this library; if not, see . */ #include "cpu.h" -#include "dyngen-exec.h" #include "helper.h" #include "helper_regs.h" @@ -28,7 +27,8 @@ /*****************************************************************************/ /* Exceptions processing helpers */ -void helper_raise_exception_err(uint32_t exception, uint32_t error_code) +void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, + uint32_t error_code) { #if 0 printf("Raise exception %3x code : %d\n", exception, error_code); @@ -38,22 +38,22 @@ void helper_raise_exception_err(uint32_t exception, uint32_t error_code) cpu_loop_exit(env); } -void helper_raise_exception(uint32_t exception) +void helper_raise_exception(CPUPPCState *env, uint32_t exception) { - helper_raise_exception_err(exception, 0); + helper_raise_exception_err(env, exception, 0); } #if !defined(CONFIG_USER_ONLY) -void helper_store_msr(target_ulong val) +void helper_store_msr(CPUPPCState *env, target_ulong val) { val = hreg_store_msr(env, val, 0); if (val != 0) { env->interrupt_request |= CPU_INTERRUPT_EXITTB; - helper_raise_exception(val); + helper_raise_exception(env, val); } } -static inline void do_rfi(target_ulong nip, target_ulong msr, +static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr, target_ulong msrm, int keep_msrh) { #if defined(TARGET_PPC64) @@ -83,73 +83,77 @@ static inline void do_rfi(target_ulong nip, target_ulong msr, env->interrupt_request |= CPU_INTERRUPT_EXITTB; } -void helper_rfi(void) +void helper_rfi(CPUPPCState *env) { - do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], + do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], ~((target_ulong)0x783F0000), 1); } #if defined(TARGET_PPC64) -void helper_rfid(void) +void helper_rfid(CPUPPCState *env) { - do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], + do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], ~((target_ulong)0x783F0000), 0); } -void helper_hrfid(void) +void helper_hrfid(CPUPPCState *env) { - do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1], + do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1], ~((target_ulong)0x783F0000), 0); } #endif /*****************************************************************************/ /* Embedded PowerPC specific helpers */ -void helper_40x_rfci(void) +void helper_40x_rfci(CPUPPCState *env) { - do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3], + do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3], ~((target_ulong)0xFFFF0000), 0); } -void helper_rfci(void) +void helper_rfci(CPUPPCState *env) { - do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1, + do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1, ~((target_ulong)0x3FFF0000), 0); } -void helper_rfdi(void) +void helper_rfdi(CPUPPCState *env) { - do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1, + do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1, ~((target_ulong)0x3FFF0000), 0); } -void helper_rfmci(void) +void helper_rfmci(CPUPPCState *env) { - do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1, + do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1, ~((target_ulong)0x3FFF0000), 0); } #endif -void helper_tw(target_ulong arg1, target_ulong arg2, uint32_t flags) +void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, + uint32_t flags) { if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) || ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_TRAP); } } #if defined(TARGET_PPC64) -void helper_td(target_ulong arg1, target_ulong arg2, uint32_t flags) +void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, + uint32_t flags) { if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) || ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_TRAP); } } #endif @@ -158,9 +162,9 @@ void helper_td(target_ulong arg1, target_ulong arg2, uint32_t flags) /*****************************************************************************/ /* PowerPC 601 specific instructions (POWER bridge) */ -void helper_rfsvc(void) +void helper_rfsvc(CPUPPCState *env) { - do_rfi(env->lr, env->ctr, 0x0000FFFF, 0); + do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0); } /* Embedded.Processor Control */ @@ -187,7 +191,7 @@ static int dbell2irq(target_ulong rb) return irq; } -void helper_msgclr(target_ulong rb) +void helper_msgclr(CPUPPCState *env, target_ulong rb) { int irq = dbell2irq(rb); diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 148543a8a1..a4562ae47c 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -1,22 +1,22 @@ #include "def-helper.h" -DEF_HELPER_2(raise_exception_err, void, i32, i32) -DEF_HELPER_1(raise_exception, void, i32) -DEF_HELPER_3(tw, void, tl, tl, i32) +DEF_HELPER_3(raise_exception_err, void, env, i32, i32) +DEF_HELPER_2(raise_exception, void, env, i32) +DEF_HELPER_4(tw, void, env, tl, tl, i32) #if defined(TARGET_PPC64) -DEF_HELPER_3(td, void, tl, tl, i32) +DEF_HELPER_4(td, void, env, tl, tl, i32) #endif #if !defined(CONFIG_USER_ONLY) -DEF_HELPER_1(store_msr, void, tl) -DEF_HELPER_0(rfi, void) -DEF_HELPER_0(rfsvc, void) -DEF_HELPER_0(40x_rfci, void) -DEF_HELPER_0(rfci, void) -DEF_HELPER_0(rfdi, void) -DEF_HELPER_0(rfmci, void) +DEF_HELPER_2(store_msr, void, env, tl) +DEF_HELPER_1(rfi, void, env) +DEF_HELPER_1(rfsvc, void, env) +DEF_HELPER_1(40x_rfci, void, env) +DEF_HELPER_1(rfci, void, env) +DEF_HELPER_1(rfdi, void, env) +DEF_HELPER_1(rfmci, void, env) #if defined(TARGET_PPC64) -DEF_HELPER_0(rfid, void) -DEF_HELPER_0(hrfid, void) +DEF_HELPER_1(rfid, void, env) +DEF_HELPER_1(hrfid, void, env) #endif #endif @@ -359,7 +359,7 @@ DEF_HELPER_FLAGS_2(store_sr, TCG_CALL_CONST, void, tl, tl) DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) DEF_HELPER_1(msgsnd, void, tl) -DEF_HELPER_1(msgclr, void, tl) +DEF_HELPER_2(msgclr, void, env, tl) #endif DEF_HELPER_3(dlmzb, tl, tl, tl, i32) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 2e8786071a..eedbb42d8c 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -294,7 +294,7 @@ void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb) if (likely(xer_bc != 0)) { if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) || (reg < rb && (reg + xer_bc) > rb))) { - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_LSWX); } else { @@ -709,7 +709,7 @@ static inline uint64_t fload_invalid_op_excp(int op) /* Update the floating-point enabled exception summary */ env->fpscr |= 1 << FPSCR_FEX; if (msr_fe0 != 0 || msr_fe1 != 0) { - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op); } } @@ -726,7 +726,7 @@ static inline void float_zero_divide_excp(void) /* Update the floating-point enabled exception summary */ env->fpscr |= 1 << FPSCR_FEX; if (msr_fe0 != 0 || msr_fe1 != 0) { - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX); } } @@ -995,7 +995,8 @@ void helper_float_check_status(void) (env->error_code & POWERPC_EXCP_FP)) { /* Differred floating-point exception after target FPR update */ if (msr_fe0 != 0 || msr_fe1 != 0) { - helper_raise_exception_err(env->exception_index, env->error_code); + helper_raise_exception_err(env, env->exception_index, + env->error_code); } } else { int status = get_float_exception_flags(&env->fp_status); @@ -1781,13 +1782,13 @@ target_ulong helper_load_dcr(target_ulong dcrn) if (unlikely(env->dcr_env == NULL)) { qemu_log("No DCR environment\n"); - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL); } else if (unlikely(ppc_dcr_read(env->dcr_env, (uint32_t)dcrn, &val) != 0)) { qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn); - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG); } return val; @@ -1797,13 +1798,13 @@ void helper_store_dcr(target_ulong dcrn, target_ulong val) { if (unlikely(env->dcr_env == NULL)) { qemu_log("No DCR environment\n"); - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL); } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, (uint32_t)val) != 0)) { qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn); - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG); } } @@ -3783,7 +3784,7 @@ void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx, cpu_restore_state(tb, env, retaddr); } } - helper_raise_exception_err(env->exception_index, env->error_code); + helper_raise_exception_err(env, env->exception_index, env->error_code); } env = saved_env; } @@ -3809,7 +3810,8 @@ void helper_store_sr(target_ulong sr_num, target_ulong val) void helper_store_slb(target_ulong rb, target_ulong rs) { if (ppc_store_slb(env, rb, rs) < 0) { - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL); + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL); } } @@ -3818,7 +3820,8 @@ target_ulong helper_load_slb_esid(target_ulong rb) target_ulong rt; if (ppc_load_slb_esid(env, rb, &rt) < 0) { - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL); + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL); } return rt; } @@ -3828,7 +3831,8 @@ target_ulong helper_load_slb_vsid(target_ulong rb) target_ulong rt; if (ppc_load_slb_vsid(env, rb, &rt) < 0) { - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL); + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL); } return rt; } @@ -4328,7 +4332,7 @@ void helper_booke206_tlbwe(void) tlb = booke206_cur_tlb(env); if (!tlb) { - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL); } @@ -4338,7 +4342,7 @@ void helper_booke206_tlbwe(void) size_ps = booke206_tlbnps(env, tlbn); if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) && !(size_ps & (1 << size_tlb))) { - helper_raise_exception_err(POWERPC_EXCP_PROGRAM, + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL); } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index cf59765405..02626ae349 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -270,7 +270,7 @@ static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t } t0 = tcg_const_i32(excp); t1 = tcg_const_i32(error); - gen_helper_raise_exception_err(t0, t1); + gen_helper_raise_exception_err(cpu_env, t0, t1); tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); ctx->exception = (excp); @@ -283,7 +283,7 @@ static inline void gen_exception(DisasContext *ctx, uint32_t excp) gen_update_nip(ctx, ctx->nip); } t0 = tcg_const_i32(excp); - gen_helper_raise_exception(t0); + gen_helper_raise_exception(cpu_env, t0); tcg_temp_free_i32(t0); ctx->exception = (excp); } @@ -297,7 +297,7 @@ static inline void gen_debug_exception(DisasContext *ctx) gen_update_nip(ctx, ctx->nip); } t0 = tcg_const_i32(EXCP_DEBUG); - gen_helper_raise_exception(t0); + gen_helper_raise_exception(cpu_env, t0); tcg_temp_free_i32(t0); } @@ -2495,7 +2495,7 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask) tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); t1 = tcg_const_i32(POWERPC_EXCP_ALIGN); t2 = tcg_const_i32(0); - gen_helper_raise_exception_err(t1, t2); + gen_helper_raise_exception_err(cpu_env, t1, t2); tcg_temp_free_i32(t1); tcg_temp_free_i32(t2); gen_set_label(l1); @@ -3662,7 +3662,7 @@ static void gen_rfi(DisasContext *ctx) return; } gen_update_cfar(ctx, ctx->nip); - gen_helper_rfi(); + gen_helper_rfi(cpu_env); gen_sync_exception(ctx); #endif } @@ -3679,7 +3679,7 @@ static void gen_rfid(DisasContext *ctx) return; } gen_update_cfar(ctx, ctx->nip); - gen_helper_rfid(); + gen_helper_rfid(cpu_env); gen_sync_exception(ctx); #endif } @@ -3694,7 +3694,7 @@ static void gen_hrfid(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } - gen_helper_hrfid(); + gen_helper_hrfid(cpu_env); gen_sync_exception(ctx); #endif } @@ -3722,7 +3722,8 @@ static void gen_tw(DisasContext *ctx) TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode)); /* Update the nip since this might generate a trap exception */ gen_update_nip(ctx, ctx->nip); - gen_helper_tw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); + gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], + t0); tcg_temp_free_i32(t0); } @@ -3733,7 +3734,7 @@ static void gen_twi(DisasContext *ctx) TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode)); /* Update the nip since this might generate a trap exception */ gen_update_nip(ctx, ctx->nip); - gen_helper_tw(cpu_gpr[rA(ctx->opcode)], t0, t1); + gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t0); tcg_temp_free_i32(t1); } @@ -3745,7 +3746,8 @@ static void gen_td(DisasContext *ctx) TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode)); /* Update the nip since this might generate a trap exception */ gen_update_nip(ctx, ctx->nip); - gen_helper_td(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); + gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], + t0); tcg_temp_free_i32(t0); } @@ -3756,7 +3758,7 @@ static void gen_tdi(DisasContext *ctx) TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode)); /* Update the nip since this might generate a trap exception */ gen_update_nip(ctx, ctx->nip); - gen_helper_td(cpu_gpr[rA(ctx->opcode)], t0, t1); + gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1); tcg_temp_free(t0); tcg_temp_free_i32(t1); } @@ -3934,7 +3936,7 @@ static void gen_mtmsrd(DisasContext *ctx) * directly from ppc_store_msr */ gen_update_nip(ctx, ctx->nip); - gen_helper_store_msr(cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_msr(cpu_env, cpu_gpr[rS(ctx->opcode)]); /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsr is not always defined as context-synchronizing */ gen_stop_exception(ctx); @@ -3972,7 +3974,7 @@ static void gen_mtmsr(DisasContext *ctx) #else tcg_gen_mov_tl(msr, cpu_gpr[rS(ctx->opcode)]); #endif - gen_helper_store_msr(msr); + gen_helper_store_msr(cpu_env, msr); /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsr is not always defined as context-synchronizing */ gen_stop_exception(ctx); @@ -5290,7 +5292,7 @@ static void gen_rfsvc(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } - gen_helper_rfsvc(); + gen_helper_rfsvc(cpu_env); gen_sync_exception(ctx); #endif } @@ -5849,7 +5851,7 @@ static void gen_rfci_40x(DisasContext *ctx) return; } /* Restore CPU state */ - gen_helper_40x_rfci(); + gen_helper_40x_rfci(cpu_env); gen_sync_exception(ctx); #endif } @@ -5864,7 +5866,7 @@ static void gen_rfci(DisasContext *ctx) return; } /* Restore CPU state */ - gen_helper_rfci(); + gen_helper_rfci(cpu_env); gen_sync_exception(ctx); #endif } @@ -5882,7 +5884,7 @@ static void gen_rfdi(DisasContext *ctx) return; } /* Restore CPU state */ - gen_helper_rfdi(); + gen_helper_rfdi(cpu_env); gen_sync_exception(ctx); #endif } @@ -5898,7 +5900,7 @@ static void gen_rfmci(DisasContext *ctx) return; } /* Restore CPU state */ - gen_helper_rfmci(); + gen_helper_rfmci(cpu_env); gen_sync_exception(ctx); #endif } @@ -6258,7 +6260,7 @@ static void gen_msgclr(DisasContext *ctx) return; } - gen_helper_msgclr(cpu_gpr[rB(ctx->opcode)]); + gen_helper_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]); #endif } From 4d5ea5e5236331b89adcacd2d68b40a849d3c9f8 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:24 +0000 Subject: [PATCH 04/72] ppc: Fix coding style in helper.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit helper.c will be spilt by the next patches, fix style issues before that. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/helper.c | 394 ++++++++++++++++++++++++++------------------ 1 file changed, 230 insertions(+), 164 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 3f7d8a464f..44f1cdd39f 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1,5 +1,5 @@ /* - * PowerPC emulation helpers for qemu. + * PowerPC emulation helpers for QEMU. * * Copyright (c) 2003-2007 Jocelyn Mayer * @@ -73,8 +73,8 @@ void (*cpu_ppc_hypercall)(CPUPPCState *); /* PowerPC MMU emulation */ #if defined(CONFIG_USER_ONLY) -int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw, - int mmu_idx) +int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, + int mmu_idx) { int exception, error_code; @@ -84,8 +84,9 @@ int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw, } else { exception = POWERPC_EXCP_DSI; error_code = 0x40000000; - if (rw) + if (rw) { error_code |= 0x02000000; + } env->spr[SPR_DAR] = address; env->spr[SPR_DSISR] = error_code; } @@ -160,8 +161,9 @@ static inline int pp_check(int key, int pp, int nx) break; } } - if (nx == 0) + if (nx == 0) { access |= PAGE_EXEC; + } return access; } @@ -171,27 +173,30 @@ static inline int check_prot(int prot, int rw, int access_type) int ret; if (access_type == ACCESS_CODE) { - if (prot & PAGE_EXEC) + if (prot & PAGE_EXEC) { ret = 0; - else + } else { ret = -2; + } } else if (rw) { - if (prot & PAGE_WRITE) + if (prot & PAGE_WRITE) { ret = 0; - else + } else { ret = -2; + } } else { - if (prot & PAGE_READ) + if (prot & PAGE_READ) { ret = 0; - else + } else { ret = -2; + } } return ret; } -static inline int _pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0, - target_ulong pte1, int h, int rw, int type) +static inline int pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0, + target_ulong pte1, int h, int rw, int type) { target_ulong ptem, mmask; int access, ret, pteh, ptev, pp; @@ -254,14 +259,14 @@ static inline int _pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0, static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0, target_ulong pte1, int h, int rw, int type) { - return _pte_check(ctx, 0, pte0, pte1, h, rw, type); + return pte_check(ctx, 0, pte0, pte1, h, rw, type); } #if defined(TARGET_PPC64) static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0, target_ulong pte1, int h, int rw, int type) { - return _pte_check(ctx, 1, pte0, pte1, h, rw, type); + return pte_check(ctx, 1, pte0, pte1, h, rw, type); } #endif @@ -291,8 +296,8 @@ static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, } /* Software driven TLB helpers */ -static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr, int way, - int is_code) +static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr, + int way, int is_code) { int nr; @@ -301,8 +306,9 @@ static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr, int wa /* Select TLB way */ nr += env->tlb_per_way * way; /* 6xx have separate TLBs for instructions and data */ - if (is_code && env->id_tlbs == 1) + if (is_code && env->id_tlbs == 1) { nr += env->nb_tlb; + } return nr; } @@ -312,11 +318,12 @@ static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env) ppc6xx_tlb_t *tlb; int nr, max; - //LOG_SWTLB("Invalidate all TLBs\n"); + /* LOG_SWTLB("Invalidate all TLBs\n"); */ /* Invalidate all defined software TLB */ max = env->nb_tlb; - if (env->id_tlbs == 1) + if (env->id_tlbs == 1) { max *= 2; + } for (nr = 0; nr < max; nr++) { tlb = &env->tlb.tlb6[nr]; pte_invalidate(&tlb->pte0); @@ -324,9 +331,9 @@ static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env) tlb_flush(env, 1); } -static inline void __ppc6xx_tlb_invalidate_virt(CPUPPCState *env, - target_ulong eaddr, - int is_code, int match_epn) +static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env, + target_ulong eaddr, + int is_code, int match_epn) { #if !defined(FLUSH_ALL_TLBS) ppc6xx_tlb_t *tlb; @@ -352,11 +359,11 @@ static inline void __ppc6xx_tlb_invalidate_virt(CPUPPCState *env, static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env, target_ulong eaddr, int is_code) { - __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0); + ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0); } -void ppc6xx_tlb_store (CPUPPCState *env, target_ulong EPN, int way, int is_code, - target_ulong pte0, target_ulong pte1) +void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, int is_code, + target_ulong pte0, target_ulong pte1) { ppc6xx_tlb_t *tlb; int nr; @@ -366,7 +373,7 @@ void ppc6xx_tlb_store (CPUPPCState *env, target_ulong EPN, int way, int is_code, LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1); /* Invalidate any pending reference in QEMU for this virtual address */ - __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1); + ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1); tlb->pte0 = pte0; tlb->pte1 = pte1; tlb->EPN = EPN; @@ -436,8 +443,8 @@ static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, } /* Perform BAT hit & translation */ -static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp, int *validp, - int *protp, target_ulong *BATu, +static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp, + int *validp, int *protp, target_ulong *BATu, target_ulong *BATl) { target_ulong bl; @@ -452,8 +459,9 @@ static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp, int *valid pp = *BATl & 0x00000003; if (pp != 0) { prot = PAGE_READ | PAGE_EXEC; - if (pp == 0x2) + if (pp == 0x2) { prot |= PAGE_WRITE; + } } } *blp = bl; @@ -475,10 +483,11 @@ static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp, valid = (*BATl >> 6) & 1; if (valid) { pp = *BATu & 0x00000003; - if (msr_pr == 0) + if (msr_pr == 0) { key = (*BATu >> 3) & 1; - else + } else { key = (*BATu >> 2) & 1; + } prot = pp_check(key, pp, 0); } *blp = bl; @@ -486,8 +495,8 @@ static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp, *protp = prot; } -static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong virtual, - int rw, int type) +static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong virtual, int rw, int type) { target_ulong *BATlt, *BATut, *BATu, *BATl; target_ulong BEPIl, BEPIu, bl; @@ -530,10 +539,11 @@ static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong virtual /* Compute access rights */ ctx->prot = prot; ret = check_prot(ctx->prot, rw, type); - if (ret == 0) + if (ret == 0) { LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n", i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', ctx->prot & PAGE_WRITE ? 'W' : '-'); + } break; } } @@ -569,7 +579,7 @@ static inline target_phys_addr_t get_pteg_offset(CPUPPCState *env, } /* PTE table lookup */ -static inline int _find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, +static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, int rw, int type, int target_page_bits) { target_phys_addr_t pteg_off; @@ -679,11 +689,12 @@ static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw, int type, int target_page_bits) { #if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) - return _find_pte(env, ctx, 1, h, rw, type, target_page_bits); + if (env->mmu_model & POWERPC_MMU_64) { + return find_pte2(env, ctx, 1, h, rw, type, target_page_bits); + } #endif - return _find_pte(env, ctx, 0, h, rw, type, target_page_bits); + return find_pte2(env, ctx, 0, h, rw, type, target_page_bits); } #if defined(TARGET_PPC64) @@ -716,7 +727,7 @@ static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr) return NULL; } -void ppc_slb_invalidate_all (CPUPPCState *env) +void ppc_slb_invalidate_all(CPUPPCState *env) { int n, do_invalidate; @@ -734,11 +745,12 @@ void ppc_slb_invalidate_all (CPUPPCState *env) do_invalidate = 1; } } - if (do_invalidate) + if (do_invalidate) { tlb_flush(env, 1); + } } -void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0) +void ppc_slb_invalidate_one(CPUPPCState *env, uint64_t T0) { ppc_slb_t *slb; @@ -758,7 +770,7 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0) } } -int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs) +int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) { int slot = rb & 0xfff; ppc_slb_t *slb = &env->slb[slot]; @@ -784,7 +796,7 @@ int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs) return 0; } -int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt) +int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, target_ulong *rt) { int slot = rb & 0xfff; ppc_slb_t *slb = &env->slb[slot]; @@ -797,7 +809,7 @@ int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt) return 0; } -int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt) +int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb, target_ulong *rt) { int slot = rb & 0xfff; ppc_slb_t *slb = &env->slb[slot]; @@ -909,21 +921,24 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx, ret = find_pte(env, ctx, 0, rw, type, target_page_bits); if (ret < 0) { /* Secondary table lookup */ - if (eaddr != 0xEFFFFFFF) + if (eaddr != 0xEFFFFFFF) { LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, vsid, ctx->ptem, ctx->hash[1]); + } ret2 = find_pte(env, ctx, 1, rw, type, target_page_bits); - if (ret2 != -1) + if (ret2 != -1) { ret = ret2; + } } } -#if defined (DUMP_PAGE_TABLES) +#if defined(DUMP_PAGE_TABLES) if (qemu_log_enabled()) { target_phys_addr_t curaddr; uint32_t a0, a1, a2, a3; + qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx "\n", sdr, mask + 0x80); for (curaddr = sdr; curaddr < (sdr + mask + 0x80); @@ -945,6 +960,7 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx, } } else { target_ulong sr; + LOG_MMU("direct store...\n"); /* Direct-store segment : absolutely *BUGGY* for now */ @@ -1018,11 +1034,13 @@ int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb, " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN, mask, (uint32_t)tlb->PID, tlb->prot); /* Check PID */ - if (tlb->PID != 0 && tlb->PID != pid) + if (tlb->PID != 0 && tlb->PID != pid) { return -1; + } /* Check effective address */ - if ((address & mask) != tlb->EPN) + if ((address & mask) != tlb->EPN) { return -1; + } *raddrp = (tlb->RPN & mask) | (address & ~mask); #if (TARGET_PHYS_ADDR_BITS >= 36) if (ext) { @@ -1035,7 +1053,7 @@ int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb, } /* Generic TLB search function for PowerPC embedded implementations */ -int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid) +int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid) { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; @@ -1080,8 +1098,9 @@ static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env, tlb = &env->tlb.tlbe[i]; if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) { end = tlb->EPN + tlb->size; - for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) + for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { tlb_flush_page(env, page); + } tlb->prot &= ~PAGE_VALID; break; } @@ -1091,8 +1110,9 @@ static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env, #endif } -static int mmu40x_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong address, int rw, int access_type) +static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong address, int rw, + int access_type) { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; @@ -1104,8 +1124,9 @@ static int mmu40x_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb.tlbe[i]; if (ppcemb_tlb_check(env, tlb, &raddr, address, - env->spr[SPR_40x_PID], 0, i) < 0) + env->spr[SPR_40x_PID], 0, i) < 0) { continue; + } zsel = (tlb->attr >> 4) & 0xF; zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3; LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n", @@ -1113,8 +1134,9 @@ static int mmu40x_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, /* Check execute enable bit */ switch (zpr) { case 0x2: - if (pr != 0) + if (pr != 0) { goto check_perms; + } /* No break here */ case 0x3: /* All accesses granted */ @@ -1135,8 +1157,9 @@ static int mmu40x_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, /* Check from TLB entry */ ctx->prot = tlb->prot; ret = check_prot(ctx->prot, rw, access_type); - if (ret == -2) + if (ret == -2) { env->spr[SPR_40x_ESR] = 0; + } break; } if (ret >= 0) { @@ -1153,7 +1176,7 @@ static int mmu40x_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, return ret; } -void store_40x_sler (CPUPPCState *env, uint32_t val) +void store_40x_sler(CPUPPCState *env, uint32_t val) { /* XXX: TO BE FIXED */ if (val != 0x00000000) { @@ -1162,12 +1185,12 @@ void store_40x_sler (CPUPPCState *env, uint32_t val) env->spr[SPR_405_SLER] = val; } -static inline int mmubooke_check_tlb (CPUPPCState *env, ppcemb_tlb_t *tlb, - target_phys_addr_t *raddr, int *prot, - target_ulong address, int rw, - int access_type, int i) +static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb, + target_phys_addr_t *raddr, int *prot, + target_ulong address, int rw, + int access_type, int i) { - int ret, _prot; + int ret, prot2; if (ppcemb_tlb_check(env, tlb, raddr, address, env->spr[SPR_BOOKE_PID], @@ -1193,9 +1216,9 @@ static inline int mmubooke_check_tlb (CPUPPCState *env, ppcemb_tlb_t *tlb, found_tlb: if (msr_pr != 0) { - _prot = tlb->prot & 0xF; + prot2 = tlb->prot & 0xF; } else { - _prot = (tlb->prot >> 4) & 0xF; + prot2 = (tlb->prot >> 4) & 0xF; } /* Check the address space */ @@ -1205,13 +1228,13 @@ found_tlb: return -1; } - *prot = _prot; - if (_prot & PAGE_EXEC) { + *prot = prot2; + if (prot2 & PAGE_EXEC) { LOG_SWTLB("%s: good TLB!\n", __func__); return 0; } - LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot); + LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2); ret = -3; } else { if (msr_dr != (tlb->attr & 1)) { @@ -1219,22 +1242,22 @@ found_tlb: return -1; } - *prot = _prot; - if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) { + *prot = prot2; + if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) { LOG_SWTLB("%s: found TLB!\n", __func__); return 0; } - LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot); + LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2); ret = -2; } return ret; } -static int mmubooke_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong address, int rw, - int access_type) +static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong address, int rw, + int access_type) { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; @@ -1285,7 +1308,8 @@ void booke206_flush_tlb(CPUPPCState *env, int flags, const int check_iprot) tlb_flush(env, 1); } -target_phys_addr_t booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb) +target_phys_addr_t booke206_tlb_to_page_size(CPUPPCState *env, + ppcmas_tlb_t *tlb) { int tlbm_size; @@ -1337,7 +1361,7 @@ static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb, int access_type) { int ret; - int _prot = 0; + int prot2 = 0; if (ppcmas_tlb_check(env, tlb, raddr, address, env->spr[SPR_BOOKE_PID]) >= 0) { @@ -1363,23 +1387,23 @@ found_tlb: if (msr_pr != 0) { if (tlb->mas7_3 & MAS3_UR) { - _prot |= PAGE_READ; + prot2 |= PAGE_READ; } if (tlb->mas7_3 & MAS3_UW) { - _prot |= PAGE_WRITE; + prot2 |= PAGE_WRITE; } if (tlb->mas7_3 & MAS3_UX) { - _prot |= PAGE_EXEC; + prot2 |= PAGE_EXEC; } } else { if (tlb->mas7_3 & MAS3_SR) { - _prot |= PAGE_READ; + prot2 |= PAGE_READ; } if (tlb->mas7_3 & MAS3_SW) { - _prot |= PAGE_WRITE; + prot2 |= PAGE_WRITE; } if (tlb->mas7_3 & MAS3_SX) { - _prot |= PAGE_EXEC; + prot2 |= PAGE_EXEC; } } @@ -1390,13 +1414,13 @@ found_tlb: return -1; } - *prot = _prot; - if (_prot & PAGE_EXEC) { + *prot = prot2; + if (prot2 & PAGE_EXEC) { LOG_SWTLB("%s: good TLB!\n", __func__); return 0; } - LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot); + LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2); ret = -3; } else { if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { @@ -1404,13 +1428,13 @@ found_tlb: return -1; } - *prot = _prot; - if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) { + *prot = prot2; + if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) { LOG_SWTLB("%s: found TLB!\n", __func__); return 0; } - LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot); + LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2); ret = -2; } @@ -1521,7 +1545,8 @@ static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf, int i; cpu_fprintf(f, "\nTLB%d:\n", tlbn); - cpu_fprintf(f, "Effective Physical Size TID TS SRWX URWX WIMGE U0123\n"); + cpu_fprintf(f, "Effective Physical Size TID TS SRWX" + " URWX WIMGE U0123\n"); entry = &env->tlb.tlbm[offset]; for (i = 0; i < tlbsize; i++, entry++) { @@ -1537,7 +1562,8 @@ static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf, ea = entry->mas2 & ~(size - 1); pa = entry->mas7_3 & ~(size - 1); - cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c U%c%c%c %c%c%c%c%c U%c%c%c%c\n", + cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c" + "U%c%c%c %c%c%c%c%c U%c%c%c%c\n", (uint64_t)ea, (uint64_t)pa, book3e_tsize_to_str[tsize], (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT, @@ -1691,8 +1717,8 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, return ret; } -int get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr, - int rw, int access_type) +int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr, + int rw, int access_type) { int ret; @@ -1721,8 +1747,9 @@ int get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr, case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_74xx: /* Try to find a BAT */ - if (env->nb_BATs != 0) + if (env->nb_BATs != 0) { ret = get_bat(env, ctx, eaddr, rw, access_type); + } #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: @@ -1766,12 +1793,13 @@ int get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr, return ret; } -target_phys_addr_t cpu_get_phys_page_debug (CPUPPCState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr) { mmu_ctx_t ctx; - if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) + if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) { return -1; + } return ctx.raddr & TARGET_PAGE_MASK; } @@ -1817,8 +1845,8 @@ static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, } /* Perform address translation */ -int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw, - int mmu_idx) +int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, + int mmu_idx) { mmu_ctx_t ctx; int access_type; @@ -1966,10 +1994,11 @@ int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw, env->exception_index = POWERPC_EXCP_DTLB; env->error_code = 0; env->spr[SPR_40x_DEAR] = address; - if (rw) + if (rw) { env->spr[SPR_40x_ESR] = 0x00800000; - else + } else { env->spr[SPR_40x_ESR] = 0x00000000; + } break; case POWERPC_MMU_32B: case POWERPC_MMU_601: @@ -1981,10 +2010,11 @@ int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw, env->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; env->spr[SPR_DAR] = address; - if (rw == 1) + if (rw == 1) { env->spr[SPR_DSISR] = 0x42000000; - else + } else { env->spr[SPR_DSISR] = 0x40000000; + } break; case POWERPC_MMU_MPC8xx: /* XXX: TODO */ @@ -2045,20 +2075,22 @@ int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw, env->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; env->spr[SPR_DAR] = address; - if (rw == 1) + if (rw == 1) { env->spr[SPR_DSISR] = 0x06000000; - else + } else { env->spr[SPR_DSISR] = 0x04000000; + } break; case ACCESS_EXT: /* eciwx or ecowx */ env->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; env->spr[SPR_DAR] = address; - if (rw == 1) + if (rw == 1) { env->spr[SPR_DSISR] = 0x06100000; - else + } else { env->spr[SPR_DSISR] = 0x04100000; + } break; default: printf("DSI: invalid exception (%d)\n", ret); @@ -2077,10 +2109,11 @@ int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw, env->error_code = 0; env->spr[SPR_DAR] = address; /* XXX: this might be incorrect */ - if (rw == 1) + if (rw == 1) { env->spr[SPR_DSISR] = 0x42000000; - else + } else { env->spr[SPR_DSISR] = 0x40000000; + } } else { env->exception_index = POWERPC_EXCP_DSEG; env->error_code = 0; @@ -2112,8 +2145,9 @@ static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu, end = base + mask + 0x00020000; LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", base, end, mask); - for (page = base; page != end; page += TARGET_PAGE_SIZE) + for (page = base; page != end; page += TARGET_PAGE_SIZE) { tlb_flush_page(env, page); + } LOG_BATS("Flush done\n"); } #endif @@ -2125,7 +2159,7 @@ static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr, nr, ul == 0 ? 'u' : 'l', value, env->nip); } -void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value) +void ppc_store_ibatu(CPUPPCState *env, int nr, target_ulong value) { target_ulong mask; @@ -2151,13 +2185,13 @@ void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value) } } -void ppc_store_ibatl (CPUPPCState *env, int nr, target_ulong value) +void ppc_store_ibatl(CPUPPCState *env, int nr, target_ulong value) { dump_store_bat(env, 'I', 1, nr, value); env->IBAT[1][nr] = value; } -void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value) +void ppc_store_dbatu(CPUPPCState *env, int nr, target_ulong value) { target_ulong mask; @@ -2183,13 +2217,13 @@ void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value) } } -void ppc_store_dbatl (CPUPPCState *env, int nr, target_ulong value) +void ppc_store_dbatl(CPUPPCState *env, int nr, target_ulong value) { dump_store_bat(env, 'D', 1, nr, value); env->DBAT[1][nr] = value; } -void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value) +void ppc_store_ibatu_601(CPUPPCState *env, int nr, target_ulong value) { target_ulong mask; #if defined(FLUSH_ALL_TLBS) @@ -2224,13 +2258,14 @@ void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value) #endif } #if defined(FLUSH_ALL_TLBS) - if (do_inval) + if (do_inval) { tlb_flush(env, 1); + } #endif } } -void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value) +void ppc_store_ibatl_601(CPUPPCState *env, int nr, target_ulong value) { target_ulong mask; #if defined(FLUSH_ALL_TLBS) @@ -2261,15 +2296,16 @@ void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value) env->IBAT[1][nr] = value; env->DBAT[1][nr] = value; #if defined(FLUSH_ALL_TLBS) - if (do_inval) + if (do_inval) { tlb_flush(env, 1); + } #endif } } /*****************************************************************************/ /* TLB management */ -void ppc_tlb_invalidate_all (CPUPPCState *env) +void ppc_tlb_invalidate_all(CPUPPCState *env) { switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: @@ -2309,7 +2345,7 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) } } -void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) +void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) { #if !defined(FLUSH_ALL_TLBS) addr &= TARGET_PAGE_MASK; @@ -2317,8 +2353,9 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_74xx: ppc6xx_tlb_invalidate_virt(env, addr, 0); - if (env->id_tlbs == 1) + if (env->id_tlbs == 1) { ppc6xx_tlb_invalidate_virt(env, addr, 1); + } break; case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_SOFT_4xx_Z: @@ -2388,7 +2425,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) /*****************************************************************************/ /* Special registers manipulation */ #if defined(TARGET_PPC64) -void ppc_store_asr (CPUPPCState *env, target_ulong value) +void ppc_store_asr(CPUPPCState *env, target_ulong value) { if (env->asr != value) { env->asr = value; @@ -2397,7 +2434,7 @@ void ppc_store_asr (CPUPPCState *env, target_ulong value) } #endif -void ppc_store_sdr1 (CPUPPCState *env, target_ulong value) +void ppc_store_sdr1(CPUPPCState *env, target_ulong value) { LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value); if (env->spr[SPR_SDR1] != value) { @@ -2425,14 +2462,14 @@ void ppc_store_sdr1 (CPUPPCState *env, target_ulong value) } #if defined(TARGET_PPC64) -target_ulong ppc_load_sr (CPUPPCState *env, int slb_nr) +target_ulong ppc_load_sr(CPUPPCState *env, int slb_nr) { - // XXX + /* XXX */ return 0; } #endif -void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value) +void ppc_store_sr(CPUPPCState *env, int srnum, target_ulong value) { LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, srnum, value, env->sr[srnum]); @@ -2465,37 +2502,38 @@ void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value) /* Invalidate 256 MB of virtual memory */ page = (16 << 20) * srnum; end = page + (16 << 20); - for (; page != end; page += TARGET_PAGE_SIZE) + for (; page != end; page += TARGET_PAGE_SIZE) { tlb_flush_page(env, page); + } } #else tlb_flush(env, 1); #endif } } -#endif /* !defined (CONFIG_USER_ONLY) */ +#endif /* !defined(CONFIG_USER_ONLY) */ /* GDBstub can read and write MSR... */ -void ppc_store_msr (CPUPPCState *env, target_ulong value) +void ppc_store_msr(CPUPPCState *env, target_ulong value) { hreg_store_msr(env, value, 0); } /*****************************************************************************/ /* Exception processing */ -#if defined (CONFIG_USER_ONLY) -void do_interrupt (CPUPPCState *env) +#if defined(CONFIG_USER_ONLY) +void do_interrupt(CPUPPCState *env) { env->exception_index = POWERPC_EXCP_NONE; env->error_code = 0; } -void ppc_hw_interrupt (CPUPPCState *env) +void ppc_hw_interrupt(CPUPPCState *env) { env->exception_index = POWERPC_EXCP_NONE; env->error_code = 0; } -#else /* defined (CONFIG_USER_ONLY) */ +#else /* defined(CONFIG_USER_ONLY) */ static inline void dump_syscall(CPUPPCState *env) { qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64 @@ -2602,23 +2640,27 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) case POWERPC_EXCP_DSI: /* Data storage exception */ LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } goto store_next; case POWERPC_EXCP_ISI: /* Instruction storage exception */ LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx "\n", msr, env->nip); - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } msr |= env->error_code; goto store_next; case POWERPC_EXCP_EXTERNAL: /* External input */ - if (lpes0 == 1) + if (lpes0 == 1) { new_msr |= (target_ulong)MSR_HVB; + } goto store_next; case POWERPC_EXCP_ALIGN: /* Alignment exception */ - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } /* XXX: this is false */ /* Get rS/rD and rA from faulting opcode */ env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; @@ -2632,29 +2674,34 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) env->error_code = 0; return; } - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } msr |= 0x00100000; - if (msr_fe0 == msr_fe1) + if (msr_fe0 == msr_fe1) { goto store_next; + } msr |= 0x00010000; break; case POWERPC_EXCP_INVAL: LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } msr |= 0x00080000; env->spr[SPR_BOOKE_ESR] = ESR_PIL; break; case POWERPC_EXCP_PRIV: - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } msr |= 0x00040000; env->spr[SPR_BOOKE_ESR] = ESR_PPR; break; case POWERPC_EXCP_TRAP: - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } msr |= 0x00020000; env->spr[SPR_BOOKE_ESR] = ESR_PTR; break; @@ -2666,8 +2713,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) } goto store_current; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } goto store_current; case POWERPC_EXCP_SYSCALL: /* System call exception */ dump_syscall(env); @@ -2676,14 +2724,16 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) cpu_ppc_hypercall(env); return; } - if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) + if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) { new_msr |= (target_ulong)MSR_HVB; + } goto store_next; case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ goto store_current; case POWERPC_EXCP_DECR: /* Decrementer exception */ - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } goto store_next; case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ /* FIT on 4xx */ @@ -2758,12 +2808,14 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) } goto store_next; case POWERPC_EXCP_DSEG: /* Data segment exception */ - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } goto store_next; case POWERPC_EXCP_ISEG: /* Instruction segment exception */ - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } goto store_next; case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ srr0 = SPR_HSRR0; @@ -2772,8 +2824,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) new_msr |= env->msr & ((target_ulong)1 << MSR_RI); goto store_next; case POWERPC_EXCP_TRACE: /* Trace exception */ - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } goto store_next; case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ srr0 = SPR_HSRR0; @@ -2800,8 +2853,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) new_msr |= env->msr & ((target_ulong)1 << MSR_RI); goto store_next; case POWERPC_EXCP_VPU: /* Vector unavailable exception */ - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } goto store_current; case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ LOG_EXCP("PIT exception\n"); @@ -2820,8 +2874,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) "is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ - if (lpes1 == 0) /* XXX: check this */ + if (lpes1 == 0) { /* XXX: check this */ new_msr |= (target_ulong)MSR_HVB; + } switch (excp_model) { case POWERPC_EXCP_602: case POWERPC_EXCP_603: @@ -2838,8 +2893,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) } break; case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ - if (lpes1 == 0) /* XXX: check this */ + if (lpes1 == 0) { /* XXX: check this */ new_msr |= (target_ulong)MSR_HVB; + } switch (excp_model) { case POWERPC_EXCP_602: case POWERPC_EXCP_603: @@ -2856,8 +2912,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) } break; case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ - if (lpes1 == 0) /* XXX: check this */ + if (lpes1 == 0) { /* XXX: check this */ new_msr |= (target_ulong)MSR_HVB; + } switch (excp_model) { case POWERPC_EXCP_602: case POWERPC_EXCP_603: @@ -2872,21 +2929,23 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) goto tlb_miss; case POWERPC_EXCP_7x5: tlb_miss: -#if defined (DEBUG_SOFTWARE_TLB) +#if defined(DEBUG_SOFTWARE_TLB) if (qemu_log_enabled()) { const char *es; target_ulong *miss, *cmp; int en; + if (excp == POWERPC_EXCP_IFTLB) { es = "I"; en = 'I'; miss = &env->spr[SPR_IMISS]; cmp = &env->spr[SPR_ICMP]; } else { - if (excp == POWERPC_EXCP_DLTLB) + if (excp == POWERPC_EXCP_DLTLB) { es = "DL"; - else + } else { es = "DS"; + } en = 'D'; miss = &env->spr[SPR_DMISS]; cmp = &env->spr[SPR_DCMP]; @@ -2905,21 +2964,23 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) break; case POWERPC_EXCP_74xx: tlb_miss_74xx: -#if defined (DEBUG_SOFTWARE_TLB) +#if defined(DEBUG_SOFTWARE_TLB) if (qemu_log_enabled()) { const char *es; target_ulong *miss, *cmp; int en; + if (excp == POWERPC_EXCP_IFTLB) { es = "I"; en = 'I'; miss = &env->spr[SPR_TLBMISS]; cmp = &env->spr[SPR_PTEHI]; } else { - if (excp == POWERPC_EXCP_DLTLB) + if (excp == POWERPC_EXCP_DLTLB) { es = "DL"; - else + } else { es = "DS"; + } en = 'D'; miss = &env->spr[SPR_TLBMISS]; cmp = &env->spr[SPR_PTEHI]; @@ -2959,8 +3020,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) "is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ - if (lpes1 == 0) + if (lpes1 == 0) { new_msr |= (target_ulong)MSR_HVB; + } /* XXX: TODO */ cpu_abort(env, "Performance counter exception is not implemented yet !\n"); @@ -3005,13 +3067,16 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) /* Save MSR */ env->spr[srr1] = msr; /* If any alternate SRR register are defined, duplicate saved values */ - if (asrr0 != -1) + if (asrr0 != -1) { env->spr[asrr0] = env->spr[srr0]; - if (asrr1 != -1) + } + if (asrr1 != -1) { env->spr[asrr1] = env->spr[srr1]; + } /* If we disactivated any translation, flush TLBs */ - if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) + if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) { tlb_flush(env, 1); + } if (msr_ile) { new_msr |= (target_ulong)1 << MSR_LE; @@ -3058,12 +3123,12 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) } } -void do_interrupt (CPUPPCState *env) +void do_interrupt(CPUPPCState *env) { powerpc_excp(env, env->excp_model, env->exception_index); } -void ppc_hw_interrupt (CPUPPCState *env) +void ppc_hw_interrupt(CPUPPCState *env) { int hdice; @@ -3180,7 +3245,7 @@ void ppc_hw_interrupt (CPUPPCState *env) } #endif /* !CONFIG_USER_ONLY */ -void cpu_dump_rfi (target_ulong RA, target_ulong msr) +void cpu_dump_rfi(target_ulong RA, target_ulong msr) { qemu_log("Return from exception at " TARGET_FMT_lx " with flags " TARGET_FMT_lx "\n", RA, msr); @@ -3193,8 +3258,9 @@ PowerPCCPU *cpu_ppc_init(const char *cpu_model) const ppc_def_t *def; def = cpu_ppc_find_by_name(cpu_model); - if (!def) + if (!def) { return NULL; + } cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU)); env = &cpu->env; From c79c73f6a9e989f9e0ae4323dcc2fad30897acce Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:25 +0000 Subject: [PATCH 05/72] ppc: Move exception helpers from helper.c to excp_helper.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move exception helpers from helper.c to excp_helper.c and make cpu_dump_rfi() static. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 2 - target-ppc/excp_helper.c | 745 +++++++++++++++++++++++++++++++++++++++ target-ppc/helper.c | 744 -------------------------------------- 3 files changed, 745 insertions(+), 746 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 77a28580af..32cfcefb07 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1117,8 +1117,6 @@ int get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, target_ulong vaddr, void do_interrupt (CPUPPCState *env); void ppc_hw_interrupt (CPUPPCState *env); -void cpu_dump_rfi (target_ulong RA, target_ulong msr); - #if !defined(CONFIG_USER_ONLY) void ppc6xx_tlb_store (CPUPPCState *env, target_ulong EPN, int way, int is_code, target_ulong pte0, target_ulong pte1); diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index c153f4ac92..7fa7a59b4f 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -24,6 +24,751 @@ //#define DEBUG_OP //#define DEBUG_EXCEPTIONS +#ifdef DEBUG_EXCEPTIONS +# define LOG_EXCP(...) qemu_log(__VA_ARGS__) +#else +# define LOG_EXCP(...) do { } while (0) +#endif + +/*****************************************************************************/ +/* PowerPC Hypercall emulation */ + +void (*cpu_ppc_hypercall)(CPUPPCState *); + +/*****************************************************************************/ +/* Exception processing */ +#if defined(CONFIG_USER_ONLY) +void do_interrupt(CPUPPCState *env) +{ + env->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; +} + +void ppc_hw_interrupt(CPUPPCState *env) +{ + env->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; +} +#else /* defined(CONFIG_USER_ONLY) */ +static inline void dump_syscall(CPUPPCState *env) +{ + qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64 + " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 + " nip=" TARGET_FMT_lx "\n", + ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), + ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), + ppc_dump_gpr(env, 6), env->nip); +} + +/* Note that this function should be greatly optimized + * when called with a constant excp, from ppc_hw_interrupt + */ +static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) +{ + target_ulong msr, new_msr, vector; + int srr0, srr1, asrr0, asrr1; + int lpes0, lpes1, lev; + + if (0) { + /* XXX: find a suitable condition to enable the hypervisor mode */ + lpes0 = (env->spr[SPR_LPCR] >> 1) & 1; + lpes1 = (env->spr[SPR_LPCR] >> 2) & 1; + } else { + /* Those values ensure we won't enter the hypervisor mode */ + lpes0 = 0; + lpes1 = 1; + } + + qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx + " => %08x (%02x)\n", env->nip, excp, env->error_code); + + /* new srr1 value excluding must-be-zero bits */ + msr = env->msr & ~0x783f0000ULL; + + /* new interrupt handler msr */ + new_msr = env->msr & ((target_ulong)1 << MSR_ME); + + /* target registers */ + srr0 = SPR_SRR0; + srr1 = SPR_SRR1; + asrr0 = -1; + asrr1 = -1; + + switch (excp) { + case POWERPC_EXCP_NONE: + /* Should never happen */ + return; + case POWERPC_EXCP_CRITICAL: /* Critical input */ + switch (excp_model) { + case POWERPC_EXCP_40x: + srr0 = SPR_40x_SRR2; + srr1 = SPR_40x_SRR3; + break; + case POWERPC_EXCP_BOOKE: + srr0 = SPR_BOOKE_CSRR0; + srr1 = SPR_BOOKE_CSRR1; + break; + case POWERPC_EXCP_G2: + break; + default: + goto excp_invalid; + } + goto store_next; + case POWERPC_EXCP_MCHECK: /* Machine check exception */ + if (msr_me == 0) { + /* Machine check exception is not enabled. + * Enter checkstop state. + */ + if (qemu_log_enabled()) { + qemu_log("Machine check while not allowed. " + "Entering checkstop state\n"); + } else { + fprintf(stderr, "Machine check while not allowed. " + "Entering checkstop state\n"); + } + env->halted = 1; + env->interrupt_request |= CPU_INTERRUPT_EXITTB; + } + if (0) { + /* XXX: find a suitable condition to enable the hypervisor mode */ + new_msr |= (target_ulong)MSR_HVB; + } + + /* machine check exceptions don't have ME set */ + new_msr &= ~((target_ulong)1 << MSR_ME); + + /* XXX: should also have something loaded in DAR / DSISR */ + switch (excp_model) { + case POWERPC_EXCP_40x: + srr0 = SPR_40x_SRR2; + srr1 = SPR_40x_SRR3; + break; + case POWERPC_EXCP_BOOKE: + srr0 = SPR_BOOKE_MCSRR0; + srr1 = SPR_BOOKE_MCSRR1; + asrr0 = SPR_BOOKE_CSRR0; + asrr1 = SPR_BOOKE_CSRR1; + break; + default: + break; + } + goto store_next; + case POWERPC_EXCP_DSI: /* Data storage exception */ + LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx + "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + goto store_next; + case POWERPC_EXCP_ISI: /* Instruction storage exception */ + LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx + "\n", msr, env->nip); + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + msr |= env->error_code; + goto store_next; + case POWERPC_EXCP_EXTERNAL: /* External input */ + if (lpes0 == 1) { + new_msr |= (target_ulong)MSR_HVB; + } + goto store_next; + case POWERPC_EXCP_ALIGN: /* Alignment exception */ + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + /* XXX: this is false */ + /* Get rS/rD and rA from faulting opcode */ + env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; + goto store_current; + case POWERPC_EXCP_PROGRAM: /* Program exception */ + switch (env->error_code & ~0xF) { + case POWERPC_EXCP_FP: + if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + LOG_EXCP("Ignore floating point exception\n"); + env->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; + return; + } + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + msr |= 0x00100000; + if (msr_fe0 == msr_fe1) { + goto store_next; + } + msr |= 0x00010000; + break; + case POWERPC_EXCP_INVAL: + LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + msr |= 0x00080000; + env->spr[SPR_BOOKE_ESR] = ESR_PIL; + break; + case POWERPC_EXCP_PRIV: + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + msr |= 0x00040000; + env->spr[SPR_BOOKE_ESR] = ESR_PPR; + break; + case POWERPC_EXCP_TRAP: + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + msr |= 0x00020000; + env->spr[SPR_BOOKE_ESR] = ESR_PTR; + break; + default: + /* Should never occur */ + cpu_abort(env, "Invalid program exception %d. Aborting\n", + env->error_code); + break; + } + goto store_current; + case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + goto store_current; + case POWERPC_EXCP_SYSCALL: /* System call exception */ + dump_syscall(env); + lev = env->error_code; + if ((lev == 1) && cpu_ppc_hypercall) { + cpu_ppc_hypercall(env); + return; + } + if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) { + new_msr |= (target_ulong)MSR_HVB; + } + goto store_next; + case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ + goto store_current; + case POWERPC_EXCP_DECR: /* Decrementer exception */ + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + goto store_next; + case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ + /* FIT on 4xx */ + LOG_EXCP("FIT exception\n"); + goto store_next; + case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ + LOG_EXCP("WDT exception\n"); + switch (excp_model) { + case POWERPC_EXCP_BOOKE: + srr0 = SPR_BOOKE_CSRR0; + srr1 = SPR_BOOKE_CSRR1; + break; + default: + break; + } + goto store_next; + case POWERPC_EXCP_DTLB: /* Data TLB error */ + goto store_next; + case POWERPC_EXCP_ITLB: /* Instruction TLB error */ + goto store_next; + case POWERPC_EXCP_DEBUG: /* Debug interrupt */ + switch (excp_model) { + case POWERPC_EXCP_BOOKE: + srr0 = SPR_BOOKE_DSRR0; + srr1 = SPR_BOOKE_DSRR1; + asrr0 = SPR_BOOKE_CSRR0; + asrr1 = SPR_BOOKE_CSRR1; + break; + default: + break; + } + /* XXX: TODO */ + cpu_abort(env, "Debug exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ + env->spr[SPR_BOOKE_ESR] = ESR_SPV; + goto store_current; + case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ + /* XXX: TODO */ + cpu_abort(env, "Embedded floating point data exception " + "is not implemented yet !\n"); + env->spr[SPR_BOOKE_ESR] = ESR_SPV; + goto store_next; + case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ + /* XXX: TODO */ + cpu_abort(env, "Embedded floating point round exception " + "is not implemented yet !\n"); + env->spr[SPR_BOOKE_ESR] = ESR_SPV; + goto store_next; + case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ + /* XXX: TODO */ + cpu_abort(env, + "Performance counter exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ + goto store_next; + case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ + srr0 = SPR_BOOKE_CSRR0; + srr1 = SPR_BOOKE_CSRR1; + goto store_next; + case POWERPC_EXCP_RESET: /* System reset exception */ + if (msr_pow) { + /* indicate that we resumed from power save mode */ + msr |= 0x10000; + } else { + new_msr &= ~((target_ulong)1 << MSR_ME); + } + + if (0) { + /* XXX: find a suitable condition to enable the hypervisor mode */ + new_msr |= (target_ulong)MSR_HVB; + } + goto store_next; + case POWERPC_EXCP_DSEG: /* Data segment exception */ + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + goto store_next; + case POWERPC_EXCP_ISEG: /* Instruction segment exception */ + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + goto store_next; + case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ + srr0 = SPR_HSRR0; + srr1 = SPR_HSRR1; + new_msr |= (target_ulong)MSR_HVB; + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + goto store_next; + case POWERPC_EXCP_TRACE: /* Trace exception */ + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + goto store_next; + case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ + srr0 = SPR_HSRR0; + srr1 = SPR_HSRR1; + new_msr |= (target_ulong)MSR_HVB; + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + goto store_next; + case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ + srr0 = SPR_HSRR0; + srr1 = SPR_HSRR1; + new_msr |= (target_ulong)MSR_HVB; + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + goto store_next; + case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ + srr0 = SPR_HSRR0; + srr1 = SPR_HSRR1; + new_msr |= (target_ulong)MSR_HVB; + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + goto store_next; + case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ + srr0 = SPR_HSRR0; + srr1 = SPR_HSRR1; + new_msr |= (target_ulong)MSR_HVB; + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + goto store_next; + case POWERPC_EXCP_VPU: /* Vector unavailable exception */ + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + goto store_current; + case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ + LOG_EXCP("PIT exception\n"); + goto store_next; + case POWERPC_EXCP_IO: /* IO error exception */ + /* XXX: TODO */ + cpu_abort(env, "601 IO error exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_RUNM: /* Run mode exception */ + /* XXX: TODO */ + cpu_abort(env, "601 run mode exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_EMUL: /* Emulation trap exception */ + /* XXX: TODO */ + cpu_abort(env, "602 emulation trap exception " + "is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ + if (lpes1 == 0) { /* XXX: check this */ + new_msr |= (target_ulong)MSR_HVB; + } + switch (excp_model) { + case POWERPC_EXCP_602: + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: + goto tlb_miss_tgpr; + case POWERPC_EXCP_7x5: + goto tlb_miss; + case POWERPC_EXCP_74xx: + goto tlb_miss_74xx; + default: + cpu_abort(env, "Invalid instruction TLB miss exception\n"); + break; + } + break; + case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ + if (lpes1 == 0) { /* XXX: check this */ + new_msr |= (target_ulong)MSR_HVB; + } + switch (excp_model) { + case POWERPC_EXCP_602: + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: + goto tlb_miss_tgpr; + case POWERPC_EXCP_7x5: + goto tlb_miss; + case POWERPC_EXCP_74xx: + goto tlb_miss_74xx; + default: + cpu_abort(env, "Invalid data load TLB miss exception\n"); + break; + } + break; + case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ + if (lpes1 == 0) { /* XXX: check this */ + new_msr |= (target_ulong)MSR_HVB; + } + switch (excp_model) { + case POWERPC_EXCP_602: + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: + tlb_miss_tgpr: + /* Swap temporary saved registers with GPRs */ + 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: +#if defined(DEBUG_SOFTWARE_TLB) + if (qemu_log_enabled()) { + const char *es; + target_ulong *miss, *cmp; + int en; + + if (excp == POWERPC_EXCP_IFTLB) { + es = "I"; + en = 'I'; + miss = &env->spr[SPR_IMISS]; + cmp = &env->spr[SPR_ICMP]; + } else { + if (excp == POWERPC_EXCP_DLTLB) { + es = "DL"; + } else { + es = "DS"; + } + en = 'D'; + miss = &env->spr[SPR_DMISS]; + cmp = &env->spr[SPR_DCMP]; + } + qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " + TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " + TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, + env->spr[SPR_HASH1], env->spr[SPR_HASH2], + env->error_code); + } +#endif + msr |= env->crf[0] << 28; + msr |= env->error_code; /* key, D/I, S/L bits */ + /* Set way using a LRU mechanism */ + msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; + break; + case POWERPC_EXCP_74xx: + tlb_miss_74xx: +#if defined(DEBUG_SOFTWARE_TLB) + if (qemu_log_enabled()) { + const char *es; + target_ulong *miss, *cmp; + int en; + + if (excp == POWERPC_EXCP_IFTLB) { + es = "I"; + en = 'I'; + miss = &env->spr[SPR_TLBMISS]; + cmp = &env->spr[SPR_PTEHI]; + } else { + if (excp == POWERPC_EXCP_DLTLB) { + es = "DL"; + } else { + es = "DS"; + } + en = 'D'; + miss = &env->spr[SPR_TLBMISS]; + cmp = &env->spr[SPR_PTEHI]; + } + qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " + TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, + env->error_code); + } +#endif + msr |= env->error_code; /* key bit */ + break; + default: + cpu_abort(env, "Invalid data store TLB miss exception\n"); + break; + } + goto store_next; + case POWERPC_EXCP_FPA: /* Floating-point assist exception */ + /* XXX: TODO */ + cpu_abort(env, "Floating point assist exception " + "is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_DABR: /* Data address breakpoint */ + /* XXX: TODO */ + cpu_abort(env, "DABR exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ + /* XXX: TODO */ + cpu_abort(env, "IABR exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_SMI: /* System management interrupt */ + /* XXX: TODO */ + cpu_abort(env, "SMI exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_THERM: /* Thermal interrupt */ + /* XXX: TODO */ + cpu_abort(env, "Thermal management exception " + "is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + /* XXX: TODO */ + cpu_abort(env, + "Performance counter exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_VPUA: /* Vector assist exception */ + /* XXX: TODO */ + cpu_abort(env, "VPU assist exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_SOFTP: /* Soft patch exception */ + /* XXX: TODO */ + cpu_abort(env, + "970 soft-patch exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_MAINT: /* Maintenance exception */ + /* XXX: TODO */ + cpu_abort(env, + "970 maintenance exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ + /* XXX: TODO */ + cpu_abort(env, "Maskable external exception " + "is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ + /* XXX: TODO */ + cpu_abort(env, "Non maskable external exception " + "is not implemented yet !\n"); + goto store_next; + default: + excp_invalid: + cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp); + break; + store_current: + /* save current instruction location */ + env->spr[srr0] = env->nip - 4; + break; + store_next: + /* save next instruction location */ + env->spr[srr0] = env->nip; + break; + } + /* Save MSR */ + env->spr[srr1] = msr; + /* If any alternate SRR register are defined, duplicate saved values */ + if (asrr0 != -1) { + env->spr[asrr0] = env->spr[srr0]; + } + if (asrr1 != -1) { + env->spr[asrr1] = env->spr[srr1]; + } + /* If we disactivated any translation, flush TLBs */ + if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) { + tlb_flush(env, 1); + } + + if (msr_ile) { + new_msr |= (target_ulong)1 << MSR_LE; + } + + /* Jump to handler */ + vector = env->excp_vectors[excp]; + if (vector == (target_ulong)-1ULL) { + cpu_abort(env, "Raised an exception without defined vector %d\n", + excp); + } + vector |= env->excp_prefix; +#if defined(TARGET_PPC64) + if (excp_model == POWERPC_EXCP_BOOKE) { + if (!msr_icm) { + vector = (uint32_t)vector; + } else { + new_msr |= (target_ulong)1 << MSR_CM; + } + } else { + if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) { + 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 & env->msr_mask; + hreg_compute_hflags(env); + env->nip = vector; + /* Reset exception state */ + env->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; + + if ((env->mmu_model == POWERPC_MMU_BOOKE) || + (env->mmu_model == POWERPC_MMU_BOOKE206)) { + /* XXX: The BookE changes address space when switching modes, + we should probably implement that as different MMU indexes, + but for the moment we do it the slow way and flush all. */ + tlb_flush(env, 1); + } +} + +void do_interrupt(CPUPPCState *env) +{ + powerpc_excp(env, env->excp_model, env->exception_index); +} + +void ppc_hw_interrupt(CPUPPCState *env) +{ + int hdice; + +#if 0 + qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n", + __func__, env, env->pending_interrupts, + env->interrupt_request, (int)msr_me, (int)msr_ee); +#endif + /* External reset */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET); + return; + } + /* Machine check exception */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK); + return; + } +#if 0 /* TODO */ + /* External debug exception */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG); + return; + } +#endif + if (0) { + /* XXX: find a suitable condition to enable the hypervisor mode */ + hdice = env->spr[SPR_LPCR] & 1; + } else { + 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); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR); + return; + } + } + if (msr_ce != 0) { + /* External critical interrupt */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { + /* Taking a critical external interrupt does not clear the external + * critical interrupt status + */ +#if 0 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT); +#endif + powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL); + return; + } + } + if (msr_ee != 0) { + /* Watchdog timer on embedded PowerPC */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT); + return; + } + if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI); + return; + } + /* Fixed interval timer on embedded PowerPC */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT); + return; + } + /* Programmable interval timer on embedded PowerPC */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT); + return; + } + /* Decrementer exception */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR); + return; + } + /* External interrupt */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { + /* Taking an external interrupt does not clear the external + * interrupt status + */ +#if 0 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); +#endif + powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL); + return; + } + if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI); + return; + } + if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM); + return; + } + /* Thermal interrupt */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM); + return; + } + } +} +#endif /* !CONFIG_USER_ONLY */ + +#if defined(DEBUG_OP) +static void cpu_dump_rfi(target_ulong RA, target_ulong msr) +{ + qemu_log("Return from exception at " TARGET_FMT_lx " with flags " + TARGET_FMT_lx "\n", RA, msr); +} +#endif + /*****************************************************************************/ /* Exceptions processing helpers */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 44f1cdd39f..17e72a9013 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -28,7 +28,6 @@ //#define DEBUG_SLB //#define DEBUG_SOFTWARE_TLB //#define DUMP_PAGE_TABLES -//#define DEBUG_EXCEPTIONS //#define FLUSH_ALL_TLBS #ifdef DEBUG_MMU @@ -58,17 +57,6 @@ # define LOG_SLB(...) do { } while (0) #endif -#ifdef DEBUG_EXCEPTIONS -# define LOG_EXCP(...) qemu_log(__VA_ARGS__) -#else -# define LOG_EXCP(...) do { } while (0) -#endif - -/*****************************************************************************/ -/* PowerPC Hypercall emulation */ - -void (*cpu_ppc_hypercall)(CPUPPCState *); - /*****************************************************************************/ /* PowerPC MMU emulation */ @@ -2519,738 +2507,6 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value) hreg_store_msr(env, value, 0); } -/*****************************************************************************/ -/* Exception processing */ -#if defined(CONFIG_USER_ONLY) -void do_interrupt(CPUPPCState *env) -{ - env->exception_index = POWERPC_EXCP_NONE; - env->error_code = 0; -} - -void ppc_hw_interrupt(CPUPPCState *env) -{ - env->exception_index = POWERPC_EXCP_NONE; - env->error_code = 0; -} -#else /* defined(CONFIG_USER_ONLY) */ -static inline void dump_syscall(CPUPPCState *env) -{ - qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64 - " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 - " nip=" TARGET_FMT_lx "\n", - ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), - ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), - ppc_dump_gpr(env, 6), env->nip); -} - -/* Note that this function should be greatly optimized - * when called with a constant excp, from ppc_hw_interrupt - */ -static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) -{ - target_ulong msr, new_msr, vector; - int srr0, srr1, asrr0, asrr1; - int lpes0, lpes1, lev; - - if (0) { - /* XXX: find a suitable condition to enable the hypervisor mode */ - lpes0 = (env->spr[SPR_LPCR] >> 1) & 1; - lpes1 = (env->spr[SPR_LPCR] >> 2) & 1; - } else { - /* Those values ensure we won't enter the hypervisor mode */ - lpes0 = 0; - lpes1 = 1; - } - - qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx - " => %08x (%02x)\n", env->nip, excp, env->error_code); - - /* new srr1 value excluding must-be-zero bits */ - msr = env->msr & ~0x783f0000ULL; - - /* new interrupt handler msr */ - new_msr = env->msr & ((target_ulong)1 << MSR_ME); - - /* target registers */ - srr0 = SPR_SRR0; - srr1 = SPR_SRR1; - asrr0 = -1; - asrr1 = -1; - - switch (excp) { - case POWERPC_EXCP_NONE: - /* Should never happen */ - return; - case POWERPC_EXCP_CRITICAL: /* Critical input */ - switch (excp_model) { - case POWERPC_EXCP_40x: - srr0 = SPR_40x_SRR2; - srr1 = SPR_40x_SRR3; - break; - case POWERPC_EXCP_BOOKE: - srr0 = SPR_BOOKE_CSRR0; - srr1 = SPR_BOOKE_CSRR1; - break; - case POWERPC_EXCP_G2: - break; - default: - goto excp_invalid; - } - goto store_next; - case POWERPC_EXCP_MCHECK: /* Machine check exception */ - if (msr_me == 0) { - /* Machine check exception is not enabled. - * Enter checkstop state. - */ - if (qemu_log_enabled()) { - qemu_log("Machine check while not allowed. " - "Entering checkstop state\n"); - } else { - fprintf(stderr, "Machine check while not allowed. " - "Entering checkstop state\n"); - } - env->halted = 1; - env->interrupt_request |= CPU_INTERRUPT_EXITTB; - } - if (0) { - /* XXX: find a suitable condition to enable the hypervisor mode */ - new_msr |= (target_ulong)MSR_HVB; - } - - /* machine check exceptions don't have ME set */ - new_msr &= ~((target_ulong)1 << MSR_ME); - - /* XXX: should also have something loaded in DAR / DSISR */ - switch (excp_model) { - case POWERPC_EXCP_40x: - srr0 = SPR_40x_SRR2; - srr1 = SPR_40x_SRR3; - break; - case POWERPC_EXCP_BOOKE: - srr0 = SPR_BOOKE_MCSRR0; - srr1 = SPR_BOOKE_MCSRR1; - asrr0 = SPR_BOOKE_CSRR0; - asrr1 = SPR_BOOKE_CSRR1; - break; - default: - break; - } - goto store_next; - case POWERPC_EXCP_DSI: /* Data storage exception */ - LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx - "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - goto store_next; - case POWERPC_EXCP_ISI: /* Instruction storage exception */ - LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx - "\n", msr, env->nip); - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - msr |= env->error_code; - goto store_next; - case POWERPC_EXCP_EXTERNAL: /* External input */ - if (lpes0 == 1) { - new_msr |= (target_ulong)MSR_HVB; - } - goto store_next; - case POWERPC_EXCP_ALIGN: /* Alignment exception */ - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - /* XXX: this is false */ - /* Get rS/rD and rA from faulting opcode */ - env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; - goto store_current; - case POWERPC_EXCP_PROGRAM: /* Program exception */ - switch (env->error_code & ~0xF) { - case POWERPC_EXCP_FP: - if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { - LOG_EXCP("Ignore floating point exception\n"); - env->exception_index = POWERPC_EXCP_NONE; - env->error_code = 0; - return; - } - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - msr |= 0x00100000; - if (msr_fe0 == msr_fe1) { - goto store_next; - } - msr |= 0x00010000; - break; - case POWERPC_EXCP_INVAL: - LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - msr |= 0x00080000; - env->spr[SPR_BOOKE_ESR] = ESR_PIL; - break; - case POWERPC_EXCP_PRIV: - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - msr |= 0x00040000; - env->spr[SPR_BOOKE_ESR] = ESR_PPR; - break; - case POWERPC_EXCP_TRAP: - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - msr |= 0x00020000; - env->spr[SPR_BOOKE_ESR] = ESR_PTR; - break; - default: - /* Should never occur */ - cpu_abort(env, "Invalid program exception %d. Aborting\n", - env->error_code); - break; - } - goto store_current; - case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - goto store_current; - case POWERPC_EXCP_SYSCALL: /* System call exception */ - dump_syscall(env); - lev = env->error_code; - if ((lev == 1) && cpu_ppc_hypercall) { - cpu_ppc_hypercall(env); - return; - } - if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) { - new_msr |= (target_ulong)MSR_HVB; - } - goto store_next; - case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ - goto store_current; - case POWERPC_EXCP_DECR: /* Decrementer exception */ - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - goto store_next; - case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ - /* FIT on 4xx */ - LOG_EXCP("FIT exception\n"); - goto store_next; - case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ - LOG_EXCP("WDT exception\n"); - switch (excp_model) { - case POWERPC_EXCP_BOOKE: - srr0 = SPR_BOOKE_CSRR0; - srr1 = SPR_BOOKE_CSRR1; - break; - default: - break; - } - goto store_next; - case POWERPC_EXCP_DTLB: /* Data TLB error */ - goto store_next; - case POWERPC_EXCP_ITLB: /* Instruction TLB error */ - goto store_next; - case POWERPC_EXCP_DEBUG: /* Debug interrupt */ - switch (excp_model) { - case POWERPC_EXCP_BOOKE: - srr0 = SPR_BOOKE_DSRR0; - srr1 = SPR_BOOKE_DSRR1; - asrr0 = SPR_BOOKE_CSRR0; - asrr1 = SPR_BOOKE_CSRR1; - break; - default: - break; - } - /* XXX: TODO */ - cpu_abort(env, "Debug exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ - env->spr[SPR_BOOKE_ESR] = ESR_SPV; - goto store_current; - case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ - /* XXX: TODO */ - cpu_abort(env, "Embedded floating point data exception " - "is not implemented yet !\n"); - env->spr[SPR_BOOKE_ESR] = ESR_SPV; - goto store_next; - case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ - /* XXX: TODO */ - cpu_abort(env, "Embedded floating point round exception " - "is not implemented yet !\n"); - env->spr[SPR_BOOKE_ESR] = ESR_SPV; - goto store_next; - case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ - /* XXX: TODO */ - cpu_abort(env, - "Performance counter exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ - goto store_next; - case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ - srr0 = SPR_BOOKE_CSRR0; - srr1 = SPR_BOOKE_CSRR1; - goto store_next; - case POWERPC_EXCP_RESET: /* System reset exception */ - if (msr_pow) { - /* indicate that we resumed from power save mode */ - msr |= 0x10000; - } else { - new_msr &= ~((target_ulong)1 << MSR_ME); - } - - if (0) { - /* XXX: find a suitable condition to enable the hypervisor mode */ - new_msr |= (target_ulong)MSR_HVB; - } - goto store_next; - case POWERPC_EXCP_DSEG: /* Data segment exception */ - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - goto store_next; - case POWERPC_EXCP_ISEG: /* Instruction segment exception */ - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - goto store_next; - case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; - case POWERPC_EXCP_TRACE: /* Trace exception */ - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - goto store_next; - case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; - case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; - case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; - case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; - case POWERPC_EXCP_VPU: /* Vector unavailable exception */ - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - goto store_current; - case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ - LOG_EXCP("PIT exception\n"); - goto store_next; - case POWERPC_EXCP_IO: /* IO error exception */ - /* XXX: TODO */ - cpu_abort(env, "601 IO error exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_RUNM: /* Run mode exception */ - /* XXX: TODO */ - cpu_abort(env, "601 run mode exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_EMUL: /* Emulation trap exception */ - /* XXX: TODO */ - cpu_abort(env, "602 emulation trap exception " - "is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ - if (lpes1 == 0) { /* XXX: check this */ - new_msr |= (target_ulong)MSR_HVB; - } - switch (excp_model) { - case POWERPC_EXCP_602: - case POWERPC_EXCP_603: - case POWERPC_EXCP_603E: - case POWERPC_EXCP_G2: - goto tlb_miss_tgpr; - case POWERPC_EXCP_7x5: - goto tlb_miss; - case POWERPC_EXCP_74xx: - goto tlb_miss_74xx; - default: - cpu_abort(env, "Invalid instruction TLB miss exception\n"); - break; - } - break; - case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ - if (lpes1 == 0) { /* XXX: check this */ - new_msr |= (target_ulong)MSR_HVB; - } - switch (excp_model) { - case POWERPC_EXCP_602: - case POWERPC_EXCP_603: - case POWERPC_EXCP_603E: - case POWERPC_EXCP_G2: - goto tlb_miss_tgpr; - case POWERPC_EXCP_7x5: - goto tlb_miss; - case POWERPC_EXCP_74xx: - goto tlb_miss_74xx; - default: - cpu_abort(env, "Invalid data load TLB miss exception\n"); - break; - } - break; - case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ - if (lpes1 == 0) { /* XXX: check this */ - new_msr |= (target_ulong)MSR_HVB; - } - switch (excp_model) { - case POWERPC_EXCP_602: - case POWERPC_EXCP_603: - case POWERPC_EXCP_603E: - case POWERPC_EXCP_G2: - tlb_miss_tgpr: - /* Swap temporary saved registers with GPRs */ - 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: -#if defined(DEBUG_SOFTWARE_TLB) - if (qemu_log_enabled()) { - const char *es; - target_ulong *miss, *cmp; - int en; - - if (excp == POWERPC_EXCP_IFTLB) { - es = "I"; - en = 'I'; - miss = &env->spr[SPR_IMISS]; - cmp = &env->spr[SPR_ICMP]; - } else { - if (excp == POWERPC_EXCP_DLTLB) { - es = "DL"; - } else { - es = "DS"; - } - en = 'D'; - miss = &env->spr[SPR_DMISS]; - cmp = &env->spr[SPR_DCMP]; - } - qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " - TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " - TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, - env->spr[SPR_HASH1], env->spr[SPR_HASH2], - env->error_code); - } -#endif - msr |= env->crf[0] << 28; - msr |= env->error_code; /* key, D/I, S/L bits */ - /* Set way using a LRU mechanism */ - msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; - break; - case POWERPC_EXCP_74xx: - tlb_miss_74xx: -#if defined(DEBUG_SOFTWARE_TLB) - if (qemu_log_enabled()) { - const char *es; - target_ulong *miss, *cmp; - int en; - - if (excp == POWERPC_EXCP_IFTLB) { - es = "I"; - en = 'I'; - miss = &env->spr[SPR_TLBMISS]; - cmp = &env->spr[SPR_PTEHI]; - } else { - if (excp == POWERPC_EXCP_DLTLB) { - es = "DL"; - } else { - es = "DS"; - } - en = 'D'; - miss = &env->spr[SPR_TLBMISS]; - cmp = &env->spr[SPR_PTEHI]; - } - qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " - TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, - env->error_code); - } -#endif - msr |= env->error_code; /* key bit */ - break; - default: - cpu_abort(env, "Invalid data store TLB miss exception\n"); - break; - } - goto store_next; - case POWERPC_EXCP_FPA: /* Floating-point assist exception */ - /* XXX: TODO */ - cpu_abort(env, "Floating point assist exception " - "is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_DABR: /* Data address breakpoint */ - /* XXX: TODO */ - cpu_abort(env, "DABR exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ - /* XXX: TODO */ - cpu_abort(env, "IABR exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_SMI: /* System management interrupt */ - /* XXX: TODO */ - cpu_abort(env, "SMI exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_THERM: /* Thermal interrupt */ - /* XXX: TODO */ - cpu_abort(env, "Thermal management exception " - "is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ - if (lpes1 == 0) { - new_msr |= (target_ulong)MSR_HVB; - } - /* XXX: TODO */ - cpu_abort(env, - "Performance counter exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_VPUA: /* Vector assist exception */ - /* XXX: TODO */ - cpu_abort(env, "VPU assist exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_SOFTP: /* Soft patch exception */ - /* XXX: TODO */ - cpu_abort(env, - "970 soft-patch exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_MAINT: /* Maintenance exception */ - /* XXX: TODO */ - cpu_abort(env, - "970 maintenance exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ - /* XXX: TODO */ - cpu_abort(env, "Maskable external exception " - "is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ - /* XXX: TODO */ - cpu_abort(env, "Non maskable external exception " - "is not implemented yet !\n"); - goto store_next; - default: - excp_invalid: - cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp); - break; - store_current: - /* save current instruction location */ - env->spr[srr0] = env->nip - 4; - break; - store_next: - /* save next instruction location */ - env->spr[srr0] = env->nip; - break; - } - /* Save MSR */ - env->spr[srr1] = msr; - /* If any alternate SRR register are defined, duplicate saved values */ - if (asrr0 != -1) { - env->spr[asrr0] = env->spr[srr0]; - } - if (asrr1 != -1) { - env->spr[asrr1] = env->spr[srr1]; - } - /* If we disactivated any translation, flush TLBs */ - if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) { - tlb_flush(env, 1); - } - - if (msr_ile) { - new_msr |= (target_ulong)1 << MSR_LE; - } - - /* Jump to handler */ - vector = env->excp_vectors[excp]; - if (vector == (target_ulong)-1ULL) { - cpu_abort(env, "Raised an exception without defined vector %d\n", - excp); - } - vector |= env->excp_prefix; -#if defined(TARGET_PPC64) - if (excp_model == POWERPC_EXCP_BOOKE) { - if (!msr_icm) { - vector = (uint32_t)vector; - } else { - new_msr |= (target_ulong)1 << MSR_CM; - } - } else { - if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) { - 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 & env->msr_mask; - hreg_compute_hflags(env); - env->nip = vector; - /* Reset exception state */ - env->exception_index = POWERPC_EXCP_NONE; - env->error_code = 0; - - if ((env->mmu_model == POWERPC_MMU_BOOKE) || - (env->mmu_model == POWERPC_MMU_BOOKE206)) { - /* XXX: The BookE changes address space when switching modes, - we should probably implement that as different MMU indexes, - but for the moment we do it the slow way and flush all. */ - tlb_flush(env, 1); - } -} - -void do_interrupt(CPUPPCState *env) -{ - powerpc_excp(env, env->excp_model, env->exception_index); -} - -void ppc_hw_interrupt(CPUPPCState *env) -{ - int hdice; - -#if 0 - qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n", - __func__, env, env->pending_interrupts, - env->interrupt_request, (int)msr_me, (int)msr_ee); -#endif - /* External reset */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); - powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET); - return; - } - /* Machine check exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); - powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK); - return; - } -#if 0 /* TODO */ - /* External debug exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); - powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG); - return; - } -#endif - if (0) { - /* XXX: find a suitable condition to enable the hypervisor mode */ - hdice = env->spr[SPR_LPCR] & 1; - } else { - 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); - powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR); - return; - } - } - if (msr_ce != 0) { - /* External critical interrupt */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { - /* Taking a critical external interrupt does not clear the external - * critical interrupt status - */ -#if 0 - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT); -#endif - powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL); - return; - } - } - if (msr_ee != 0) { - /* Watchdog timer on embedded PowerPC */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); - powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT); - return; - } - if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); - powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI); - return; - } - /* Fixed interval timer on embedded PowerPC */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); - powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT); - return; - } - /* Programmable interval timer on embedded PowerPC */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); - powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT); - return; - } - /* Decrementer exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); - powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR); - return; - } - /* External interrupt */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { - /* Taking an external interrupt does not clear the external - * interrupt status - */ -#if 0 - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); -#endif - powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL); - return; - } - if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); - powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI); - return; - } - if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); - powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM); - return; - } - /* Thermal interrupt */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); - powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM); - return; - } - } -} -#endif /* !CONFIG_USER_ONLY */ - -void cpu_dump_rfi(target_ulong RA, target_ulong msr) -{ - qemu_log("Return from exception at " TARGET_FMT_lx " with flags " - TARGET_FMT_lx "\n", RA, msr); -} - PowerPCCPU *cpu_ppc_init(const char *cpu_model) { PowerPCCPU *cpu; From bd23cd45ea533580da410eed9c31692abf7584e6 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:26 +0000 Subject: [PATCH 06/72] ppc: Split FPU and SPE ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move FPU and SPE helpers from op_helper.c to fpu_helper.c. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 2 + target-ppc/fpu_helper.c | 1731 ++++++++++++++++++++++++++++++++++++++ target-ppc/op_helper.c | 1710 ------------------------------------- 3 files changed, 1733 insertions(+), 1710 deletions(-) create mode 100644 target-ppc/fpu_helper.c diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index a02b7bccde..dde916c685 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -3,5 +3,7 @@ obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o obj-y += op_helper.o helper.o obj-y += excp_helper.o +obj-y += fpu_helper.o +$(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c new file mode 100644 index 0000000000..be965d106d --- /dev/null +++ b/target-ppc/fpu_helper.c @@ -0,0 +1,1731 @@ +/* + * PowerPC floating point and SPE emulation 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, see . + */ +#include "cpu.h" +#include "dyngen-exec.h" +#include "helper.h" + +/*****************************************************************************/ +/* Floating point operations helpers */ +uint64_t helper_float32_to_float64(uint32_t arg) +{ + CPU_FloatU f; + CPU_DoubleU d; + + f.l = arg; + d.d = float32_to_float64(f.f, &env->fp_status); + return d.ll; +} + +uint32_t helper_float64_to_float32(uint64_t arg) +{ + CPU_FloatU f; + CPU_DoubleU d; + + d.ll = arg; + f.f = float64_to_float32(d.d, &env->fp_status); + return f.l; +} + +static inline int isden(float64 d) +{ + CPU_DoubleU u; + + u.d = d; + + return ((u.ll >> 52) & 0x7FF) == 0; +} + +uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf) +{ + CPU_DoubleU farg; + int isneg; + int ret; + + farg.ll = arg; + isneg = float64_is_neg(farg.d); + if (unlikely(float64_is_any_nan(farg.d))) { + if (float64_is_signaling_nan(farg.d)) { + /* Signaling NaN: flags are undefined */ + ret = 0x00; + } else { + /* Quiet NaN */ + ret = 0x11; + } + } else if (unlikely(float64_is_infinity(farg.d))) { + /* +/- infinity */ + if (isneg) { + ret = 0x09; + } else { + ret = 0x05; + } + } else { + if (float64_is_zero(farg.d)) { + /* +/- zero */ + if (isneg) { + ret = 0x12; + } else { + ret = 0x02; + } + } else { + if (isden(farg.d)) { + /* Denormalized numbers */ + ret = 0x10; + } else { + /* Normalized numbers */ + ret = 0x00; + } + if (isneg) { + ret |= 0x08; + } else { + ret |= 0x04; + } + } + } + if (set_fprf) { + /* We update FPSCR_FPRF */ + env->fpscr &= ~(0x1F << FPSCR_FPRF); + env->fpscr |= ret << FPSCR_FPRF; + } + /* We just need fpcc to update Rc1 */ + return ret & 0xF; +} + +/* Floating-point invalid operations exception */ +static inline uint64_t fload_invalid_op_excp(int op) +{ + uint64_t ret = 0; + int ve; + + ve = fpscr_ve; + switch (op) { + case POWERPC_EXCP_FP_VXSNAN: + env->fpscr |= 1 << FPSCR_VXSNAN; + break; + case POWERPC_EXCP_FP_VXSOFT: + env->fpscr |= 1 << FPSCR_VXSOFT; + break; + case POWERPC_EXCP_FP_VXISI: + /* Magnitude subtraction of infinities */ + env->fpscr |= 1 << FPSCR_VXISI; + goto update_arith; + case POWERPC_EXCP_FP_VXIDI: + /* Division of infinity by infinity */ + env->fpscr |= 1 << FPSCR_VXIDI; + goto update_arith; + case POWERPC_EXCP_FP_VXZDZ: + /* Division of zero by zero */ + env->fpscr |= 1 << FPSCR_VXZDZ; + goto update_arith; + case POWERPC_EXCP_FP_VXIMZ: + /* Multiplication of zero by infinity */ + env->fpscr |= 1 << FPSCR_VXIMZ; + goto update_arith; + case POWERPC_EXCP_FP_VXVC: + /* Ordered comparison of NaN */ + env->fpscr |= 1 << FPSCR_VXVC; + env->fpscr &= ~(0xF << FPSCR_FPCC); + env->fpscr |= 0x11 << FPSCR_FPCC; + /* We must update the target FPR before raising the exception */ + if (ve != 0) { + env->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + /* Exception is differed */ + ve = 0; + } + break; + case POWERPC_EXCP_FP_VXSQRT: + /* Square root of a negative number */ + env->fpscr |= 1 << FPSCR_VXSQRT; + update_arith: + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + if (ve == 0) { + /* Set the result to quiet NaN */ + ret = 0x7FF8000000000000ULL; + env->fpscr &= ~(0xF << FPSCR_FPCC); + env->fpscr |= 0x11 << FPSCR_FPCC; + } + break; + case POWERPC_EXCP_FP_VXCVI: + /* Invalid conversion */ + env->fpscr |= 1 << FPSCR_VXCVI; + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + if (ve == 0) { + /* Set the result to quiet NaN */ + ret = 0x7FF8000000000000ULL; + env->fpscr &= ~(0xF << FPSCR_FPCC); + env->fpscr |= 0x11 << FPSCR_FPCC; + } + break; + } + /* Update the floating-point invalid operation summary */ + env->fpscr |= 1 << FPSCR_VX; + /* Update the floating-point exception summary */ + env->fpscr |= 1 << FPSCR_FX; + if (ve != 0) { + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + if (msr_fe0 != 0 || msr_fe1 != 0) { + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_FP | op); + } + } + return ret; +} + +static inline void float_zero_divide_excp(void) +{ + env->fpscr |= 1 << FPSCR_ZX; + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + /* Update the floating-point exception summary */ + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_ze != 0) { + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + if (msr_fe0 != 0 || msr_fe1 != 0) { + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX); + } + } +} + +static inline void float_overflow_excp(void) +{ + env->fpscr |= 1 << FPSCR_OX; + /* Update the floating-point exception summary */ + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_oe != 0) { + /* XXX: should adjust the result */ + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + /* We must update the target FPR before raising the exception */ + env->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; + } else { + env->fpscr |= 1 << FPSCR_XX; + env->fpscr |= 1 << FPSCR_FI; + } +} + +static inline void float_underflow_excp(void) +{ + env->fpscr |= 1 << FPSCR_UX; + /* Update the floating-point exception summary */ + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_ue != 0) { + /* XXX: should adjust the result */ + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + /* We must update the target FPR before raising the exception */ + env->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; + } +} + +static inline void float_inexact_excp(void) +{ + env->fpscr |= 1 << FPSCR_XX; + /* Update the floating-point exception summary */ + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_xe != 0) { + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + /* We must update the target FPR before raising the exception */ + env->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; + } +} + +static inline void fpscr_set_rounding_mode(void) +{ + int rnd_type; + + /* Set rounding mode */ + switch (fpscr_rn) { + case 0: + /* Best approximation (round to nearest) */ + rnd_type = float_round_nearest_even; + break; + case 1: + /* Smaller magnitude (round toward zero) */ + rnd_type = float_round_to_zero; + break; + case 2: + /* Round toward +infinite */ + rnd_type = float_round_up; + break; + default: + case 3: + /* Round toward -infinite */ + rnd_type = float_round_down; + break; + } + set_float_rounding_mode(rnd_type, &env->fp_status); +} + +void helper_fpscr_clrbit(uint32_t bit) +{ + int prev; + + prev = (env->fpscr >> bit) & 1; + env->fpscr &= ~(1 << bit); + if (prev == 1) { + switch (bit) { + case FPSCR_RN1: + case FPSCR_RN: + fpscr_set_rounding_mode(); + break; + default: + break; + } + } +} + +void helper_fpscr_setbit(uint32_t bit) +{ + int prev; + + prev = (env->fpscr >> bit) & 1; + env->fpscr |= 1 << bit; + if (prev == 0) { + switch (bit) { + case FPSCR_VX: + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_ve) { + goto raise_ve; + } + case FPSCR_OX: + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_oe) { + goto raise_oe; + } + break; + case FPSCR_UX: + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_ue) { + goto raise_ue; + } + break; + case FPSCR_ZX: + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_ze) { + goto raise_ze; + } + break; + case FPSCR_XX: + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_xe) { + goto raise_xe; + } + break; + case FPSCR_VXSNAN: + case FPSCR_VXISI: + case FPSCR_VXIDI: + case FPSCR_VXZDZ: + case FPSCR_VXIMZ: + case FPSCR_VXVC: + case FPSCR_VXSOFT: + case FPSCR_VXSQRT: + case FPSCR_VXCVI: + env->fpscr |= 1 << FPSCR_VX; + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_ve != 0) { + goto raise_ve; + } + break; + case FPSCR_VE: + if (fpscr_vx != 0) { + raise_ve: + env->error_code = POWERPC_EXCP_FP; + if (fpscr_vxsnan) { + env->error_code |= POWERPC_EXCP_FP_VXSNAN; + } + if (fpscr_vxisi) { + env->error_code |= POWERPC_EXCP_FP_VXISI; + } + if (fpscr_vxidi) { + env->error_code |= POWERPC_EXCP_FP_VXIDI; + } + if (fpscr_vxzdz) { + env->error_code |= POWERPC_EXCP_FP_VXZDZ; + } + if (fpscr_vximz) { + env->error_code |= POWERPC_EXCP_FP_VXIMZ; + } + if (fpscr_vxvc) { + env->error_code |= POWERPC_EXCP_FP_VXVC; + } + if (fpscr_vxsoft) { + env->error_code |= POWERPC_EXCP_FP_VXSOFT; + } + if (fpscr_vxsqrt) { + env->error_code |= POWERPC_EXCP_FP_VXSQRT; + } + if (fpscr_vxcvi) { + env->error_code |= POWERPC_EXCP_FP_VXCVI; + } + goto raise_excp; + } + break; + case FPSCR_OE: + if (fpscr_ox != 0) { + raise_oe: + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; + goto raise_excp; + } + break; + case FPSCR_UE: + if (fpscr_ux != 0) { + raise_ue: + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; + goto raise_excp; + } + break; + case FPSCR_ZE: + if (fpscr_zx != 0) { + raise_ze: + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX; + goto raise_excp; + } + break; + case FPSCR_XE: + if (fpscr_xx != 0) { + raise_xe: + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; + goto raise_excp; + } + break; + case FPSCR_RN1: + case FPSCR_RN: + fpscr_set_rounding_mode(); + break; + default: + break; + raise_excp: + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + /* We have to update Rc1 before raising the exception */ + env->exception_index = POWERPC_EXCP_PROGRAM; + break; + } + } +} + +void helper_store_fpscr(uint64_t arg, uint32_t mask) +{ + /* + * We use only the 32 LSB of the incoming fpr + */ + uint32_t prev, new; + int i; + + prev = env->fpscr; + new = (uint32_t)arg; + new &= ~0x60000000; + new |= prev & 0x60000000; + for (i = 0; i < 8; i++) { + if (mask & (1 << i)) { + env->fpscr &= ~(0xF << (4 * i)); + env->fpscr |= new & (0xF << (4 * i)); + } + } + /* Update VX and FEX */ + if (fpscr_ix != 0) { + env->fpscr |= 1 << FPSCR_VX; + } else { + env->fpscr &= ~(1 << FPSCR_VX); + } + if ((fpscr_ex & fpscr_eex) != 0) { + env->fpscr |= 1 << FPSCR_FEX; + env->exception_index = POWERPC_EXCP_PROGRAM; + /* XXX: we should compute it properly */ + env->error_code = POWERPC_EXCP_FP; + } else { + env->fpscr &= ~(1 << FPSCR_FEX); + } + fpscr_set_rounding_mode(); +} + +void helper_float_check_status(void) +{ + if (env->exception_index == POWERPC_EXCP_PROGRAM && + (env->error_code & POWERPC_EXCP_FP)) { + /* Differred floating-point exception after target FPR update */ + if (msr_fe0 != 0 || msr_fe1 != 0) { + helper_raise_exception_err(env, env->exception_index, + env->error_code); + } + } else { + int status = get_float_exception_flags(&env->fp_status); + if (status & float_flag_divbyzero) { + float_zero_divide_excp(); + } else if (status & float_flag_overflow) { + float_overflow_excp(); + } else if (status & float_flag_underflow) { + float_underflow_excp(); + } else if (status & float_flag_inexact) { + float_inexact_excp(); + } + } +} + +void helper_reset_fpstatus(void) +{ + set_float_exception_flags(0, &env->fp_status); +} + +/* fadd - fadd. */ +uint64_t helper_fadd(uint64_t arg1, uint64_t arg2) +{ + CPU_DoubleU farg1, farg2; + + farg1.ll = arg1; + farg2.ll = arg2; + + if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && + float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) { + /* Magnitude subtraction of infinities */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d))) { + /* sNaN addition */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status); + } + + return farg1.ll; +} + +/* fsub - fsub. */ +uint64_t helper_fsub(uint64_t arg1, uint64_t arg2) +{ + CPU_DoubleU farg1, farg2; + + farg1.ll = arg1; + farg2.ll = arg2; + + if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && + float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) { + /* Magnitude subtraction of infinities */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d))) { + /* sNaN subtraction */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status); + } + + return farg1.ll; +} + +/* fmul - fmul. */ +uint64_t helper_fmul(uint64_t arg1, uint64_t arg2) +{ + CPU_DoubleU farg1, farg2; + + farg1.ll = arg1; + farg2.ll = arg2; + + if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || + (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { + /* Multiplication of zero by infinity */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); + } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d))) { + /* sNaN multiplication */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); + } + + return farg1.ll; +} + +/* fdiv - fdiv. */ +uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2) +{ + CPU_DoubleU farg1, farg2; + + farg1.ll = arg1; + farg2.ll = arg2; + + if (unlikely(float64_is_infinity(farg1.d) && + float64_is_infinity(farg2.d))) { + /* Division of infinity by infinity */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI); + } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) { + /* Division of zero by zero */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ); + } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d))) { + /* sNaN division */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status); + } + + return farg1.ll; +} + +/* fabs */ +uint64_t helper_fabs(uint64_t arg) +{ + CPU_DoubleU farg; + + farg.ll = arg; + farg.d = float64_abs(farg.d); + return farg.ll; +} + +/* fnabs */ +uint64_t helper_fnabs(uint64_t arg) +{ + CPU_DoubleU farg; + + farg.ll = arg; + farg.d = float64_abs(farg.d); + farg.d = float64_chs(farg.d); + return farg.ll; +} + +/* fneg */ +uint64_t helper_fneg(uint64_t arg) +{ + CPU_DoubleU farg; + + farg.ll = arg; + farg.d = float64_chs(farg.d); + return farg.ll; +} + +/* fctiw - fctiw. */ +uint64_t helper_fctiw(uint64_t arg) +{ + CPU_DoubleU farg; + + farg.ll = arg; + + if (unlikely(float64_is_signaling_nan(farg.d))) { + /* sNaN conversion */ + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_quiet_nan(farg.d) || + float64_is_infinity(farg.d))) { + /* qNan / infinity conversion */ + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + } else { + farg.ll = float64_to_int32(farg.d, &env->fp_status); + /* XXX: higher bits are not supposed to be significant. + * to make tests easier, return the same as a real PowerPC 750 + */ + farg.ll |= 0xFFF80000ULL << 32; + } + return farg.ll; +} + +/* fctiwz - fctiwz. */ +uint64_t helper_fctiwz(uint64_t arg) +{ + CPU_DoubleU farg; + + farg.ll = arg; + + if (unlikely(float64_is_signaling_nan(farg.d))) { + /* sNaN conversion */ + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_quiet_nan(farg.d) || + float64_is_infinity(farg.d))) { + /* qNan / infinity conversion */ + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + } else { + farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status); + /* XXX: higher bits are not supposed to be significant. + * to make tests easier, return the same as a real PowerPC 750 + */ + farg.ll |= 0xFFF80000ULL << 32; + } + return farg.ll; +} + +#if defined(TARGET_PPC64) +/* fcfid - fcfid. */ +uint64_t helper_fcfid(uint64_t arg) +{ + CPU_DoubleU farg; + + farg.d = int64_to_float64(arg, &env->fp_status); + return farg.ll; +} + +/* fctid - fctid. */ +uint64_t helper_fctid(uint64_t arg) +{ + CPU_DoubleU farg; + + farg.ll = arg; + + if (unlikely(float64_is_signaling_nan(farg.d))) { + /* sNaN conversion */ + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_quiet_nan(farg.d) || + float64_is_infinity(farg.d))) { + /* qNan / infinity conversion */ + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + } else { + farg.ll = float64_to_int64(farg.d, &env->fp_status); + } + return farg.ll; +} + +/* fctidz - fctidz. */ +uint64_t helper_fctidz(uint64_t arg) +{ + CPU_DoubleU farg; + + farg.ll = arg; + + if (unlikely(float64_is_signaling_nan(farg.d))) { + /* sNaN conversion */ + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_quiet_nan(farg.d) || + float64_is_infinity(farg.d))) { + /* qNan / infinity conversion */ + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + } else { + farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status); + } + return farg.ll; +} + +#endif + +static inline uint64_t do_fri(uint64_t arg, int rounding_mode) +{ + CPU_DoubleU farg; + + farg.ll = arg; + + if (unlikely(float64_is_signaling_nan(farg.d))) { + /* sNaN round */ + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_quiet_nan(farg.d) || + float64_is_infinity(farg.d))) { + /* qNan / infinity round */ + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + } else { + set_float_rounding_mode(rounding_mode, &env->fp_status); + farg.ll = float64_round_to_int(farg.d, &env->fp_status); + /* Restore rounding mode from FPSCR */ + fpscr_set_rounding_mode(); + } + return farg.ll; +} + +uint64_t helper_frin(uint64_t arg) +{ + return do_fri(arg, float_round_nearest_even); +} + +uint64_t helper_friz(uint64_t arg) +{ + return do_fri(arg, float_round_to_zero); +} + +uint64_t helper_frip(uint64_t arg) +{ + return do_fri(arg, float_round_up); +} + +uint64_t helper_frim(uint64_t arg) +{ + return do_fri(arg, float_round_down); +} + +/* fmadd - fmadd. */ +uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) +{ + CPU_DoubleU farg1, farg2, farg3; + + farg1.ll = arg1; + farg2.ll = arg2; + farg3.ll = arg3; + + if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || + (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { + /* Multiplication of zero by infinity */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); + } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d) || + float64_is_signaling_nan(farg3.d))) { + /* sNaN operation */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + /* This is the way the PowerPC specification defines it */ + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(farg1.d, &env->fp_status); + ft1_128 = float64_to_float128(farg2.d, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + if (unlikely(float128_is_infinity(ft0_128) && + float64_is_infinity(farg3.d) && + float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { + /* Magnitude subtraction of infinities */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + } else { + ft1_128 = float64_to_float128(farg3.d, &env->fp_status); + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); + farg1.d = float128_to_float64(ft0_128, &env->fp_status); + } + } + + return farg1.ll; +} + +/* fmsub - fmsub. */ +uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) +{ + CPU_DoubleU farg1, farg2, farg3; + + farg1.ll = arg1; + farg2.ll = arg2; + farg3.ll = arg3; + + if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || + (float64_is_zero(farg1.d) && + float64_is_infinity(farg2.d)))) { + /* Multiplication of zero by infinity */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); + } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d) || + float64_is_signaling_nan(farg3.d))) { + /* sNaN operation */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + /* This is the way the PowerPC specification defines it */ + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(farg1.d, &env->fp_status); + ft1_128 = float64_to_float128(farg2.d, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + if (unlikely(float128_is_infinity(ft0_128) && + float64_is_infinity(farg3.d) && + float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { + /* Magnitude subtraction of infinities */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + } else { + ft1_128 = float64_to_float128(farg3.d, &env->fp_status); + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); + farg1.d = float128_to_float64(ft0_128, &env->fp_status); + } + } + return farg1.ll; +} + +/* fnmadd - fnmadd. */ +uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) +{ + CPU_DoubleU farg1, farg2, farg3; + + farg1.ll = arg1; + farg2.ll = arg2; + farg3.ll = arg3; + + if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || + (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { + /* Multiplication of zero by infinity */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); + } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d) || + float64_is_signaling_nan(farg3.d))) { + /* sNaN operation */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + /* This is the way the PowerPC specification defines it */ + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(farg1.d, &env->fp_status); + ft1_128 = float64_to_float128(farg2.d, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + if (unlikely(float128_is_infinity(ft0_128) && + float64_is_infinity(farg3.d) && + float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { + /* Magnitude subtraction of infinities */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + } else { + ft1_128 = float64_to_float128(farg3.d, &env->fp_status); + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); + farg1.d = float128_to_float64(ft0_128, &env->fp_status); + } + if (likely(!float64_is_any_nan(farg1.d))) { + farg1.d = float64_chs(farg1.d); + } + } + return farg1.ll; +} + +/* fnmsub - fnmsub. */ +uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) +{ + CPU_DoubleU farg1, farg2, farg3; + + farg1.ll = arg1; + farg2.ll = arg2; + farg3.ll = arg3; + + if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || + (float64_is_zero(farg1.d) && + float64_is_infinity(farg2.d)))) { + /* Multiplication of zero by infinity */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); + } else { + if (unlikely(float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d) || + float64_is_signaling_nan(farg3.d))) { + /* sNaN operation */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + /* This is the way the PowerPC specification defines it */ + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(farg1.d, &env->fp_status); + ft1_128 = float64_to_float128(farg2.d, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + if (unlikely(float128_is_infinity(ft0_128) && + float64_is_infinity(farg3.d) && + float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { + /* Magnitude subtraction of infinities */ + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + } else { + ft1_128 = float64_to_float128(farg3.d, &env->fp_status); + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); + farg1.d = float128_to_float64(ft0_128, &env->fp_status); + } + if (likely(!float64_is_any_nan(farg1.d))) { + farg1.d = float64_chs(farg1.d); + } + } + return farg1.ll; +} + +/* frsp - frsp. */ +uint64_t helper_frsp(uint64_t arg) +{ + CPU_DoubleU farg; + float32 f32; + + farg.ll = arg; + + if (unlikely(float64_is_signaling_nan(farg.d))) { + /* sNaN square root */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + f32 = float64_to_float32(farg.d, &env->fp_status); + farg.d = float32_to_float64(f32, &env->fp_status); + + return farg.ll; +} + +/* fsqrt - fsqrt. */ +uint64_t helper_fsqrt(uint64_t arg) +{ + CPU_DoubleU farg; + + farg.ll = arg; + + if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { + /* Square root of a negative nonzero number */ + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT); + } else { + if (unlikely(float64_is_signaling_nan(farg.d))) { + /* sNaN square root */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + farg.d = float64_sqrt(farg.d, &env->fp_status); + } + return farg.ll; +} + +/* fre - fre. */ +uint64_t helper_fre(uint64_t arg) +{ + CPU_DoubleU farg; + + farg.ll = arg; + + if (unlikely(float64_is_signaling_nan(farg.d))) { + /* sNaN reciprocal */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + farg.d = float64_div(float64_one, farg.d, &env->fp_status); + return farg.d; +} + +/* fres - fres. */ +uint64_t helper_fres(uint64_t arg) +{ + CPU_DoubleU farg; + float32 f32; + + farg.ll = arg; + + if (unlikely(float64_is_signaling_nan(farg.d))) { + /* sNaN reciprocal */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + farg.d = float64_div(float64_one, farg.d, &env->fp_status); + f32 = float64_to_float32(farg.d, &env->fp_status); + farg.d = float32_to_float64(f32, &env->fp_status); + + return farg.ll; +} + +/* frsqrte - frsqrte. */ +uint64_t helper_frsqrte(uint64_t arg) +{ + CPU_DoubleU farg; + float32 f32; + + farg.ll = arg; + + if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { + /* Reciprocal square root of a negative nonzero number */ + farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT); + } else { + if (unlikely(float64_is_signaling_nan(farg.d))) { + /* sNaN reciprocal square root */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } + farg.d = float64_sqrt(farg.d, &env->fp_status); + farg.d = float64_div(float64_one, farg.d, &env->fp_status); + f32 = float64_to_float32(farg.d, &env->fp_status); + farg.d = float32_to_float64(f32, &env->fp_status); + } + return farg.ll; +} + +/* fsel - fsel. */ +uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3) +{ + CPU_DoubleU farg1; + + farg1.ll = arg1; + + if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && + !float64_is_any_nan(farg1.d)) { + return arg2; + } else { + return arg3; + } +} + +void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD) +{ + CPU_DoubleU farg1, farg2; + uint32_t ret = 0; + + farg1.ll = arg1; + farg2.ll = arg2; + + if (unlikely(float64_is_any_nan(farg1.d) || + float64_is_any_nan(farg2.d))) { + ret = 0x01UL; + } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { + ret = 0x08UL; + } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) { + ret = 0x04UL; + } else { + ret = 0x02UL; + } + + env->fpscr &= ~(0x0F << FPSCR_FPRF); + env->fpscr |= ret << FPSCR_FPRF; + env->crf[crfD] = ret; + if (unlikely(ret == 0x01UL + && (float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d)))) { + /* sNaN comparison */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } +} + +void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD) +{ + CPU_DoubleU farg1, farg2; + uint32_t ret = 0; + + farg1.ll = arg1; + farg2.ll = arg2; + + if (unlikely(float64_is_any_nan(farg1.d) || + float64_is_any_nan(farg2.d))) { + ret = 0x01UL; + } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { + ret = 0x08UL; + } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) { + ret = 0x04UL; + } else { + ret = 0x02UL; + } + + env->fpscr &= ~(0x0F << FPSCR_FPRF); + env->fpscr |= ret << FPSCR_FPRF; + env->crf[crfD] = ret; + if (unlikely(ret == 0x01UL)) { + if (float64_is_signaling_nan(farg1.d) || + float64_is_signaling_nan(farg2.d)) { + /* sNaN comparison */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + POWERPC_EXCP_FP_VXVC); + } else { + /* qNaN comparison */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC); + } + } +} + +/* Single-precision floating-point conversions */ +static inline uint32_t efscfsi(uint32_t val) +{ + CPU_FloatU u; + + u.f = int32_to_float32(val, &env->vec_status); + + return u.l; +} + +static inline uint32_t efscfui(uint32_t val) +{ + CPU_FloatU u; + + u.f = uint32_to_float32(val, &env->vec_status); + + return u.l; +} + +static inline int32_t efsctsi(uint32_t val) +{ + CPU_FloatU u; + + u.l = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float32_is_quiet_nan(u.f))) { + return 0; + } + + return float32_to_int32(u.f, &env->vec_status); +} + +static inline uint32_t efsctui(uint32_t val) +{ + CPU_FloatU u; + + u.l = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float32_is_quiet_nan(u.f))) { + return 0; + } + + return float32_to_uint32(u.f, &env->vec_status); +} + +static inline uint32_t efsctsiz(uint32_t val) +{ + CPU_FloatU u; + + u.l = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float32_is_quiet_nan(u.f))) { + return 0; + } + + return float32_to_int32_round_to_zero(u.f, &env->vec_status); +} + +static inline uint32_t efsctuiz(uint32_t val) +{ + CPU_FloatU u; + + u.l = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float32_is_quiet_nan(u.f))) { + return 0; + } + + return float32_to_uint32_round_to_zero(u.f, &env->vec_status); +} + +static inline uint32_t efscfsf(uint32_t val) +{ + CPU_FloatU u; + float32 tmp; + + u.f = int32_to_float32(val, &env->vec_status); + tmp = int64_to_float32(1ULL << 32, &env->vec_status); + u.f = float32_div(u.f, tmp, &env->vec_status); + + return u.l; +} + +static inline uint32_t efscfuf(uint32_t val) +{ + CPU_FloatU u; + float32 tmp; + + u.f = uint32_to_float32(val, &env->vec_status); + tmp = uint64_to_float32(1ULL << 32, &env->vec_status); + u.f = float32_div(u.f, tmp, &env->vec_status); + + return u.l; +} + +static inline uint32_t efsctsf(uint32_t val) +{ + CPU_FloatU u; + float32 tmp; + + u.l = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float32_is_quiet_nan(u.f))) { + return 0; + } + tmp = uint64_to_float32(1ULL << 32, &env->vec_status); + u.f = float32_mul(u.f, tmp, &env->vec_status); + + return float32_to_int32(u.f, &env->vec_status); +} + +static inline uint32_t efsctuf(uint32_t val) +{ + CPU_FloatU u; + float32 tmp; + + u.l = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float32_is_quiet_nan(u.f))) { + return 0; + } + tmp = uint64_to_float32(1ULL << 32, &env->vec_status); + u.f = float32_mul(u.f, tmp, &env->vec_status); + + return float32_to_uint32(u.f, &env->vec_status); +} + +#define HELPER_SPE_SINGLE_CONV(name) \ + uint32_t helper_e##name(uint32_t val) \ + { \ + return e##name(val); \ + } +/* efscfsi */ +HELPER_SPE_SINGLE_CONV(fscfsi); +/* efscfui */ +HELPER_SPE_SINGLE_CONV(fscfui); +/* efscfuf */ +HELPER_SPE_SINGLE_CONV(fscfuf); +/* efscfsf */ +HELPER_SPE_SINGLE_CONV(fscfsf); +/* efsctsi */ +HELPER_SPE_SINGLE_CONV(fsctsi); +/* efsctui */ +HELPER_SPE_SINGLE_CONV(fsctui); +/* efsctsiz */ +HELPER_SPE_SINGLE_CONV(fsctsiz); +/* efsctuiz */ +HELPER_SPE_SINGLE_CONV(fsctuiz); +/* efsctsf */ +HELPER_SPE_SINGLE_CONV(fsctsf); +/* efsctuf */ +HELPER_SPE_SINGLE_CONV(fsctuf); + +#define HELPER_SPE_VECTOR_CONV(name) \ + uint64_t helper_ev##name(uint64_t val) \ + { \ + return ((uint64_t)e##name(val >> 32) << 32) | \ + (uint64_t)e##name(val); \ + } +/* evfscfsi */ +HELPER_SPE_VECTOR_CONV(fscfsi); +/* evfscfui */ +HELPER_SPE_VECTOR_CONV(fscfui); +/* evfscfuf */ +HELPER_SPE_VECTOR_CONV(fscfuf); +/* evfscfsf */ +HELPER_SPE_VECTOR_CONV(fscfsf); +/* evfsctsi */ +HELPER_SPE_VECTOR_CONV(fsctsi); +/* evfsctui */ +HELPER_SPE_VECTOR_CONV(fsctui); +/* evfsctsiz */ +HELPER_SPE_VECTOR_CONV(fsctsiz); +/* evfsctuiz */ +HELPER_SPE_VECTOR_CONV(fsctuiz); +/* evfsctsf */ +HELPER_SPE_VECTOR_CONV(fsctsf); +/* evfsctuf */ +HELPER_SPE_VECTOR_CONV(fsctuf); + +/* Single-precision floating-point arithmetic */ +static inline uint32_t efsadd(uint32_t op1, uint32_t op2) +{ + CPU_FloatU u1, u2; + + u1.l = op1; + u2.l = op2; + u1.f = float32_add(u1.f, u2.f, &env->vec_status); + return u1.l; +} + +static inline uint32_t efssub(uint32_t op1, uint32_t op2) +{ + CPU_FloatU u1, u2; + + u1.l = op1; + u2.l = op2; + u1.f = float32_sub(u1.f, u2.f, &env->vec_status); + return u1.l; +} + +static inline uint32_t efsmul(uint32_t op1, uint32_t op2) +{ + CPU_FloatU u1, u2; + + u1.l = op1; + u2.l = op2; + u1.f = float32_mul(u1.f, u2.f, &env->vec_status); + return u1.l; +} + +static inline uint32_t efsdiv(uint32_t op1, uint32_t op2) +{ + CPU_FloatU u1, u2; + + u1.l = op1; + u2.l = op2; + u1.f = float32_div(u1.f, u2.f, &env->vec_status); + return u1.l; +} + +#define HELPER_SPE_SINGLE_ARITH(name) \ + uint32_t helper_e##name(uint32_t op1, uint32_t op2) \ + { \ + return e##name(op1, op2); \ + } +/* efsadd */ +HELPER_SPE_SINGLE_ARITH(fsadd); +/* efssub */ +HELPER_SPE_SINGLE_ARITH(fssub); +/* efsmul */ +HELPER_SPE_SINGLE_ARITH(fsmul); +/* efsdiv */ +HELPER_SPE_SINGLE_ARITH(fsdiv); + +#define HELPER_SPE_VECTOR_ARITH(name) \ + uint64_t helper_ev##name(uint64_t op1, uint64_t op2) \ + { \ + return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \ + (uint64_t)e##name(op1, op2); \ + } +/* evfsadd */ +HELPER_SPE_VECTOR_ARITH(fsadd); +/* evfssub */ +HELPER_SPE_VECTOR_ARITH(fssub); +/* evfsmul */ +HELPER_SPE_VECTOR_ARITH(fsmul); +/* evfsdiv */ +HELPER_SPE_VECTOR_ARITH(fsdiv); + +/* Single-precision floating-point comparisons */ +static inline uint32_t efscmplt(uint32_t op1, uint32_t op2) +{ + CPU_FloatU u1, u2; + + u1.l = op1; + u2.l = op2; + return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0; +} + +static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2) +{ + CPU_FloatU u1, u2; + + u1.l = op1; + u2.l = op2; + return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4; +} + +static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2) +{ + CPU_FloatU u1, u2; + + u1.l = op1; + u2.l = op2; + return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0; +} + +static inline uint32_t efststlt(uint32_t op1, uint32_t op2) +{ + /* XXX: TODO: ignore special values (NaN, infinites, ...) */ + return efscmplt(op1, op2); +} + +static inline uint32_t efststgt(uint32_t op1, uint32_t op2) +{ + /* XXX: TODO: ignore special values (NaN, infinites, ...) */ + return efscmpgt(op1, op2); +} + +static inline uint32_t efststeq(uint32_t op1, uint32_t op2) +{ + /* XXX: TODO: ignore special values (NaN, infinites, ...) */ + return efscmpeq(op1, op2); +} + +#define HELPER_SINGLE_SPE_CMP(name) \ + uint32_t helper_e##name(uint32_t op1, uint32_t op2) \ + { \ + return e##name(op1, op2) << 2; \ + } +/* efststlt */ +HELPER_SINGLE_SPE_CMP(fststlt); +/* efststgt */ +HELPER_SINGLE_SPE_CMP(fststgt); +/* efststeq */ +HELPER_SINGLE_SPE_CMP(fststeq); +/* efscmplt */ +HELPER_SINGLE_SPE_CMP(fscmplt); +/* efscmpgt */ +HELPER_SINGLE_SPE_CMP(fscmpgt); +/* efscmpeq */ +HELPER_SINGLE_SPE_CMP(fscmpeq); + +static inline uint32_t evcmp_merge(int t0, int t1) +{ + return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1); +} + +#define HELPER_VECTOR_SPE_CMP(name) \ + uint32_t helper_ev##name(uint64_t op1, uint64_t op2) \ + { \ + return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \ + } +/* evfststlt */ +HELPER_VECTOR_SPE_CMP(fststlt); +/* evfststgt */ +HELPER_VECTOR_SPE_CMP(fststgt); +/* evfststeq */ +HELPER_VECTOR_SPE_CMP(fststeq); +/* evfscmplt */ +HELPER_VECTOR_SPE_CMP(fscmplt); +/* evfscmpgt */ +HELPER_VECTOR_SPE_CMP(fscmpgt); +/* evfscmpeq */ +HELPER_VECTOR_SPE_CMP(fscmpeq); + +/* Double-precision floating-point conversion */ +uint64_t helper_efdcfsi(uint32_t val) +{ + CPU_DoubleU u; + + u.d = int32_to_float64(val, &env->vec_status); + + return u.ll; +} + +uint64_t helper_efdcfsid(uint64_t val) +{ + CPU_DoubleU u; + + u.d = int64_to_float64(val, &env->vec_status); + + return u.ll; +} + +uint64_t helper_efdcfui(uint32_t val) +{ + CPU_DoubleU u; + + u.d = uint32_to_float64(val, &env->vec_status); + + return u.ll; +} + +uint64_t helper_efdcfuid(uint64_t val) +{ + CPU_DoubleU u; + + u.d = uint64_to_float64(val, &env->vec_status); + + return u.ll; +} + +uint32_t helper_efdctsi(uint64_t val) +{ + CPU_DoubleU u; + + u.ll = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float64_is_any_nan(u.d))) { + return 0; + } + + return float64_to_int32(u.d, &env->vec_status); +} + +uint32_t helper_efdctui(uint64_t val) +{ + CPU_DoubleU u; + + u.ll = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float64_is_any_nan(u.d))) { + return 0; + } + + return float64_to_uint32(u.d, &env->vec_status); +} + +uint32_t helper_efdctsiz(uint64_t val) +{ + CPU_DoubleU u; + + u.ll = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float64_is_any_nan(u.d))) { + return 0; + } + + return float64_to_int32_round_to_zero(u.d, &env->vec_status); +} + +uint64_t helper_efdctsidz(uint64_t val) +{ + CPU_DoubleU u; + + u.ll = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float64_is_any_nan(u.d))) { + return 0; + } + + return float64_to_int64_round_to_zero(u.d, &env->vec_status); +} + +uint32_t helper_efdctuiz(uint64_t val) +{ + CPU_DoubleU u; + + u.ll = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float64_is_any_nan(u.d))) { + return 0; + } + + return float64_to_uint32_round_to_zero(u.d, &env->vec_status); +} + +uint64_t helper_efdctuidz(uint64_t val) +{ + CPU_DoubleU u; + + u.ll = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float64_is_any_nan(u.d))) { + return 0; + } + + return float64_to_uint64_round_to_zero(u.d, &env->vec_status); +} + +uint64_t helper_efdcfsf(uint32_t val) +{ + CPU_DoubleU u; + float64 tmp; + + u.d = int32_to_float64(val, &env->vec_status); + tmp = int64_to_float64(1ULL << 32, &env->vec_status); + u.d = float64_div(u.d, tmp, &env->vec_status); + + return u.ll; +} + +uint64_t helper_efdcfuf(uint32_t val) +{ + CPU_DoubleU u; + float64 tmp; + + u.d = uint32_to_float64(val, &env->vec_status); + tmp = int64_to_float64(1ULL << 32, &env->vec_status); + u.d = float64_div(u.d, tmp, &env->vec_status); + + return u.ll; +} + +uint32_t helper_efdctsf(uint64_t val) +{ + CPU_DoubleU u; + float64 tmp; + + u.ll = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float64_is_any_nan(u.d))) { + return 0; + } + tmp = uint64_to_float64(1ULL << 32, &env->vec_status); + u.d = float64_mul(u.d, tmp, &env->vec_status); + + return float64_to_int32(u.d, &env->vec_status); +} + +uint32_t helper_efdctuf(uint64_t val) +{ + CPU_DoubleU u; + float64 tmp; + + u.ll = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(float64_is_any_nan(u.d))) { + return 0; + } + tmp = uint64_to_float64(1ULL << 32, &env->vec_status); + u.d = float64_mul(u.d, tmp, &env->vec_status); + + return float64_to_uint32(u.d, &env->vec_status); +} + +uint32_t helper_efscfd(uint64_t val) +{ + CPU_DoubleU u1; + CPU_FloatU u2; + + u1.ll = val; + u2.f = float64_to_float32(u1.d, &env->vec_status); + + return u2.l; +} + +uint64_t helper_efdcfs(uint32_t val) +{ + CPU_DoubleU u2; + CPU_FloatU u1; + + u1.l = val; + u2.d = float32_to_float64(u1.f, &env->vec_status); + + return u2.ll; +} + +/* Double precision fixed-point arithmetic */ +uint64_t helper_efdadd(uint64_t op1, uint64_t op2) +{ + CPU_DoubleU u1, u2; + + u1.ll = op1; + u2.ll = op2; + u1.d = float64_add(u1.d, u2.d, &env->vec_status); + return u1.ll; +} + +uint64_t helper_efdsub(uint64_t op1, uint64_t op2) +{ + CPU_DoubleU u1, u2; + + u1.ll = op1; + u2.ll = op2; + u1.d = float64_sub(u1.d, u2.d, &env->vec_status); + return u1.ll; +} + +uint64_t helper_efdmul(uint64_t op1, uint64_t op2) +{ + CPU_DoubleU u1, u2; + + u1.ll = op1; + u2.ll = op2; + u1.d = float64_mul(u1.d, u2.d, &env->vec_status); + return u1.ll; +} + +uint64_t helper_efddiv(uint64_t op1, uint64_t op2) +{ + CPU_DoubleU u1, u2; + + u1.ll = op1; + u2.ll = op2; + u1.d = float64_div(u1.d, u2.d, &env->vec_status); + return u1.ll; +} + +/* Double precision floating point helpers */ +uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2) +{ + CPU_DoubleU u1, u2; + + u1.ll = op1; + u2.ll = op2; + return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0; +} + +uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2) +{ + CPU_DoubleU u1, u2; + + u1.ll = op1; + u2.ll = op2; + return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4; +} + +uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2) +{ + CPU_DoubleU u1, u2; + + u1.ll = op1; + u2.ll = op2; + return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0; +} + +uint32_t helper_efdcmplt(uint64_t op1, uint64_t op2) +{ + /* XXX: TODO: test special values (NaN, infinites, ...) */ + return helper_efdtstlt(op1, op2); +} + +uint32_t helper_efdcmpgt(uint64_t op1, uint64_t op2) +{ + /* XXX: TODO: test special values (NaN, infinites, ...) */ + return helper_efdtstgt(op1, op2); +} + +uint32_t helper_efdcmpeq(uint64_t op1, uint64_t op2) +{ + /* XXX: TODO: test special values (NaN, infinites, ...) */ + return helper_efdtsteq(op1, op2); +} diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index eedbb42d8c..3f677f6da1 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -546,1099 +546,6 @@ target_ulong helper_popcntw(target_ulong val) } #endif -/*****************************************************************************/ -/* Floating point operations helpers */ -uint64_t helper_float32_to_float64(uint32_t arg) -{ - CPU_FloatU f; - CPU_DoubleU d; - - f.l = arg; - d.d = float32_to_float64(f.f, &env->fp_status); - return d.ll; -} - -uint32_t helper_float64_to_float32(uint64_t arg) -{ - CPU_FloatU f; - CPU_DoubleU d; - - d.ll = arg; - f.f = float64_to_float32(d.d, &env->fp_status); - return f.l; -} - -static inline int isden(float64 d) -{ - CPU_DoubleU u; - - u.d = d; - - return ((u.ll >> 52) & 0x7FF) == 0; -} - -uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf) -{ - CPU_DoubleU farg; - int isneg; - int ret; - - farg.ll = arg; - isneg = float64_is_neg(farg.d); - if (unlikely(float64_is_any_nan(farg.d))) { - if (float64_is_signaling_nan(farg.d)) { - /* Signaling NaN: flags are undefined */ - ret = 0x00; - } else { - /* Quiet NaN */ - ret = 0x11; - } - } else if (unlikely(float64_is_infinity(farg.d))) { - /* +/- infinity */ - if (isneg) { - ret = 0x09; - } else { - ret = 0x05; - } - } else { - if (float64_is_zero(farg.d)) { - /* +/- zero */ - if (isneg) { - ret = 0x12; - } else { - ret = 0x02; - } - } else { - if (isden(farg.d)) { - /* Denormalized numbers */ - ret = 0x10; - } else { - /* Normalized numbers */ - ret = 0x00; - } - if (isneg) { - ret |= 0x08; - } else { - ret |= 0x04; - } - } - } - if (set_fprf) { - /* We update FPSCR_FPRF */ - env->fpscr &= ~(0x1F << FPSCR_FPRF); - env->fpscr |= ret << FPSCR_FPRF; - } - /* We just need fpcc to update Rc1 */ - return ret & 0xF; -} - -/* Floating-point invalid operations exception */ -static inline uint64_t fload_invalid_op_excp(int op) -{ - uint64_t ret = 0; - int ve; - - ve = fpscr_ve; - switch (op) { - case POWERPC_EXCP_FP_VXSNAN: - env->fpscr |= 1 << FPSCR_VXSNAN; - break; - case POWERPC_EXCP_FP_VXSOFT: - env->fpscr |= 1 << FPSCR_VXSOFT; - break; - case POWERPC_EXCP_FP_VXISI: - /* Magnitude subtraction of infinities */ - env->fpscr |= 1 << FPSCR_VXISI; - goto update_arith; - case POWERPC_EXCP_FP_VXIDI: - /* Division of infinity by infinity */ - env->fpscr |= 1 << FPSCR_VXIDI; - goto update_arith; - case POWERPC_EXCP_FP_VXZDZ: - /* Division of zero by zero */ - env->fpscr |= 1 << FPSCR_VXZDZ; - goto update_arith; - case POWERPC_EXCP_FP_VXIMZ: - /* Multiplication of zero by infinity */ - env->fpscr |= 1 << FPSCR_VXIMZ; - goto update_arith; - case POWERPC_EXCP_FP_VXVC: - /* Ordered comparison of NaN */ - env->fpscr |= 1 << FPSCR_VXVC; - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; - /* We must update the target FPR before raising the exception */ - if (ve != 0) { - env->exception_index = POWERPC_EXCP_PROGRAM; - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; - /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; - /* Exception is differed */ - ve = 0; - } - break; - case POWERPC_EXCP_FP_VXSQRT: - /* Square root of a negative number */ - env->fpscr |= 1 << FPSCR_VXSQRT; - update_arith: - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); - if (ve == 0) { - /* Set the result to quiet NaN */ - ret = 0x7FF8000000000000ULL; - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; - } - break; - case POWERPC_EXCP_FP_VXCVI: - /* Invalid conversion */ - env->fpscr |= 1 << FPSCR_VXCVI; - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); - if (ve == 0) { - /* Set the result to quiet NaN */ - ret = 0x7FF8000000000000ULL; - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; - } - break; - } - /* Update the floating-point invalid operation summary */ - env->fpscr |= 1 << FPSCR_VX; - /* Update the floating-point exception summary */ - env->fpscr |= 1 << FPSCR_FX; - if (ve != 0) { - /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; - if (msr_fe0 != 0 || msr_fe1 != 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_FP | op); - } - } - return ret; -} - -static inline void float_zero_divide_excp(void) -{ - env->fpscr |= 1 << FPSCR_ZX; - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); - /* Update the floating-point exception summary */ - env->fpscr |= 1 << FPSCR_FX; - if (fpscr_ze != 0) { - /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; - if (msr_fe0 != 0 || msr_fe1 != 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX); - } - } -} - -static inline void float_overflow_excp(void) -{ - env->fpscr |= 1 << FPSCR_OX; - /* Update the floating-point exception summary */ - env->fpscr |= 1 << FPSCR_FX; - if (fpscr_oe != 0) { - /* XXX: should adjust the result */ - /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; - /* We must update the target FPR before raising the exception */ - env->exception_index = POWERPC_EXCP_PROGRAM; - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; - } else { - env->fpscr |= 1 << FPSCR_XX; - env->fpscr |= 1 << FPSCR_FI; - } -} - -static inline void float_underflow_excp(void) -{ - env->fpscr |= 1 << FPSCR_UX; - /* Update the floating-point exception summary */ - env->fpscr |= 1 << FPSCR_FX; - if (fpscr_ue != 0) { - /* XXX: should adjust the result */ - /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; - /* We must update the target FPR before raising the exception */ - env->exception_index = POWERPC_EXCP_PROGRAM; - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; - } -} - -static inline void float_inexact_excp(void) -{ - env->fpscr |= 1 << FPSCR_XX; - /* Update the floating-point exception summary */ - env->fpscr |= 1 << FPSCR_FX; - if (fpscr_xe != 0) { - /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; - /* We must update the target FPR before raising the exception */ - env->exception_index = POWERPC_EXCP_PROGRAM; - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; - } -} - -static inline void fpscr_set_rounding_mode(void) -{ - int rnd_type; - - /* Set rounding mode */ - switch (fpscr_rn) { - case 0: - /* Best approximation (round to nearest) */ - rnd_type = float_round_nearest_even; - break; - case 1: - /* Smaller magnitude (round toward zero) */ - rnd_type = float_round_to_zero; - break; - case 2: - /* Round toward +infinite */ - rnd_type = float_round_up; - break; - default: - case 3: - /* Round toward -infinite */ - rnd_type = float_round_down; - break; - } - set_float_rounding_mode(rnd_type, &env->fp_status); -} - -void helper_fpscr_clrbit(uint32_t bit) -{ - int prev; - - prev = (env->fpscr >> bit) & 1; - env->fpscr &= ~(1 << bit); - if (prev == 1) { - switch (bit) { - case FPSCR_RN1: - case FPSCR_RN: - fpscr_set_rounding_mode(); - break; - default: - break; - } - } -} - -void helper_fpscr_setbit(uint32_t bit) -{ - int prev; - - prev = (env->fpscr >> bit) & 1; - env->fpscr |= 1 << bit; - if (prev == 0) { - switch (bit) { - case FPSCR_VX: - env->fpscr |= 1 << FPSCR_FX; - if (fpscr_ve) { - goto raise_ve; - } - case FPSCR_OX: - env->fpscr |= 1 << FPSCR_FX; - if (fpscr_oe) { - goto raise_oe; - } - break; - case FPSCR_UX: - env->fpscr |= 1 << FPSCR_FX; - if (fpscr_ue) { - goto raise_ue; - } - break; - case FPSCR_ZX: - env->fpscr |= 1 << FPSCR_FX; - if (fpscr_ze) { - goto raise_ze; - } - break; - case FPSCR_XX: - env->fpscr |= 1 << FPSCR_FX; - if (fpscr_xe) { - goto raise_xe; - } - break; - case FPSCR_VXSNAN: - case FPSCR_VXISI: - case FPSCR_VXIDI: - case FPSCR_VXZDZ: - case FPSCR_VXIMZ: - case FPSCR_VXVC: - case FPSCR_VXSOFT: - case FPSCR_VXSQRT: - case FPSCR_VXCVI: - env->fpscr |= 1 << FPSCR_VX; - env->fpscr |= 1 << FPSCR_FX; - if (fpscr_ve != 0) { - goto raise_ve; - } - break; - case FPSCR_VE: - if (fpscr_vx != 0) { - raise_ve: - env->error_code = POWERPC_EXCP_FP; - if (fpscr_vxsnan) { - env->error_code |= POWERPC_EXCP_FP_VXSNAN; - } - if (fpscr_vxisi) { - env->error_code |= POWERPC_EXCP_FP_VXISI; - } - if (fpscr_vxidi) { - env->error_code |= POWERPC_EXCP_FP_VXIDI; - } - if (fpscr_vxzdz) { - env->error_code |= POWERPC_EXCP_FP_VXZDZ; - } - if (fpscr_vximz) { - env->error_code |= POWERPC_EXCP_FP_VXIMZ; - } - if (fpscr_vxvc) { - env->error_code |= POWERPC_EXCP_FP_VXVC; - } - if (fpscr_vxsoft) { - env->error_code |= POWERPC_EXCP_FP_VXSOFT; - } - if (fpscr_vxsqrt) { - env->error_code |= POWERPC_EXCP_FP_VXSQRT; - } - if (fpscr_vxcvi) { - env->error_code |= POWERPC_EXCP_FP_VXCVI; - } - goto raise_excp; - } - break; - case FPSCR_OE: - if (fpscr_ox != 0) { - raise_oe: - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; - goto raise_excp; - } - break; - case FPSCR_UE: - if (fpscr_ux != 0) { - raise_ue: - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; - goto raise_excp; - } - break; - case FPSCR_ZE: - if (fpscr_zx != 0) { - raise_ze: - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX; - goto raise_excp; - } - break; - case FPSCR_XE: - if (fpscr_xx != 0) { - raise_xe: - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; - goto raise_excp; - } - break; - case FPSCR_RN1: - case FPSCR_RN: - fpscr_set_rounding_mode(); - break; - default: - break; - raise_excp: - /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; - /* We have to update Rc1 before raising the exception */ - env->exception_index = POWERPC_EXCP_PROGRAM; - break; - } - } -} - -void helper_store_fpscr(uint64_t arg, uint32_t mask) -{ - /* - * We use only the 32 LSB of the incoming fpr - */ - uint32_t prev, new; - int i; - - prev = env->fpscr; - new = (uint32_t)arg; - new &= ~0x60000000; - new |= prev & 0x60000000; - for (i = 0; i < 8; i++) { - if (mask & (1 << i)) { - env->fpscr &= ~(0xF << (4 * i)); - env->fpscr |= new & (0xF << (4 * i)); - } - } - /* Update VX and FEX */ - if (fpscr_ix != 0) { - env->fpscr |= 1 << FPSCR_VX; - } else { - env->fpscr &= ~(1 << FPSCR_VX); - } - if ((fpscr_ex & fpscr_eex) != 0) { - env->fpscr |= 1 << FPSCR_FEX; - env->exception_index = POWERPC_EXCP_PROGRAM; - /* XXX: we should compute it properly */ - env->error_code = POWERPC_EXCP_FP; - } else { - env->fpscr &= ~(1 << FPSCR_FEX); - } - fpscr_set_rounding_mode(); -} - -void helper_float_check_status(void) -{ - if (env->exception_index == POWERPC_EXCP_PROGRAM && - (env->error_code & POWERPC_EXCP_FP)) { - /* Differred floating-point exception after target FPR update */ - if (msr_fe0 != 0 || msr_fe1 != 0) { - helper_raise_exception_err(env, env->exception_index, - env->error_code); - } - } else { - int status = get_float_exception_flags(&env->fp_status); - if (status & float_flag_divbyzero) { - float_zero_divide_excp(); - } else if (status & float_flag_overflow) { - float_overflow_excp(); - } else if (status & float_flag_underflow) { - float_underflow_excp(); - } else if (status & float_flag_inexact) { - float_inexact_excp(); - } - } -} - -void helper_reset_fpstatus(void) -{ - set_float_exception_flags(0, &env->fp_status); -} - -/* fadd - fadd. */ -uint64_t helper_fadd(uint64_t arg1, uint64_t arg2) -{ - CPU_DoubleU farg1, farg2; - - farg1.ll = arg1; - farg2.ll = arg2; - - if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && - float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) { - /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d))) { - /* sNaN addition */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status); - } - - return farg1.ll; -} - -/* fsub - fsub. */ -uint64_t helper_fsub(uint64_t arg1, uint64_t arg2) -{ - CPU_DoubleU farg1, farg2; - - farg1.ll = arg1; - farg2.ll = arg2; - - if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && - float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) { - /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d))) { - /* sNaN subtraction */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status); - } - - return farg1.ll; -} - -/* fmul - fmul. */ -uint64_t helper_fmul(uint64_t arg1, uint64_t arg2) -{ - CPU_DoubleU farg1, farg2; - - farg1.ll = arg1; - farg2.ll = arg2; - - if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || - (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { - /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d))) { - /* sNaN multiplication */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); - } - - return farg1.ll; -} - -/* fdiv - fdiv. */ -uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2) -{ - CPU_DoubleU farg1, farg2; - - farg1.ll = arg1; - farg2.ll = arg2; - - if (unlikely(float64_is_infinity(farg1.d) && - float64_is_infinity(farg2.d))) { - /* Division of infinity by infinity */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI); - } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) { - /* Division of zero by zero */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d))) { - /* sNaN division */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status); - } - - return farg1.ll; -} - -/* fabs */ -uint64_t helper_fabs(uint64_t arg) -{ - CPU_DoubleU farg; - - farg.ll = arg; - farg.d = float64_abs(farg.d); - return farg.ll; -} - -/* fnabs */ -uint64_t helper_fnabs(uint64_t arg) -{ - CPU_DoubleU farg; - - farg.ll = arg; - farg.d = float64_abs(farg.d); - farg.d = float64_chs(farg.d); - return farg.ll; -} - -/* fneg */ -uint64_t helper_fneg(uint64_t arg) -{ - CPU_DoubleU farg; - - farg.ll = arg; - farg.d = float64_chs(farg.d); - return farg.ll; -} - -/* fctiw - fctiw. */ -uint64_t helper_fctiw(uint64_t arg) -{ - CPU_DoubleU farg; - - farg.ll = arg; - - if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | - POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_quiet_nan(farg.d) || - float64_is_infinity(farg.d))) { - /* qNan / infinity conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); - } else { - farg.ll = float64_to_int32(farg.d, &env->fp_status); - /* XXX: higher bits are not supposed to be significant. - * to make tests easier, return the same as a real PowerPC 750 - */ - farg.ll |= 0xFFF80000ULL << 32; - } - return farg.ll; -} - -/* fctiwz - fctiwz. */ -uint64_t helper_fctiwz(uint64_t arg) -{ - CPU_DoubleU farg; - - farg.ll = arg; - - if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | - POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_quiet_nan(farg.d) || - float64_is_infinity(farg.d))) { - /* qNan / infinity conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); - } else { - farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status); - /* XXX: higher bits are not supposed to be significant. - * to make tests easier, return the same as a real PowerPC 750 - */ - farg.ll |= 0xFFF80000ULL << 32; - } - return farg.ll; -} - -#if defined(TARGET_PPC64) -/* fcfid - fcfid. */ -uint64_t helper_fcfid(uint64_t arg) -{ - CPU_DoubleU farg; - - farg.d = int64_to_float64(arg, &env->fp_status); - return farg.ll; -} - -/* fctid - fctid. */ -uint64_t helper_fctid(uint64_t arg) -{ - CPU_DoubleU farg; - - farg.ll = arg; - - if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | - POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_quiet_nan(farg.d) || - float64_is_infinity(farg.d))) { - /* qNan / infinity conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); - } else { - farg.ll = float64_to_int64(farg.d, &env->fp_status); - } - return farg.ll; -} - -/* fctidz - fctidz. */ -uint64_t helper_fctidz(uint64_t arg) -{ - CPU_DoubleU farg; - - farg.ll = arg; - - if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | - POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_quiet_nan(farg.d) || - float64_is_infinity(farg.d))) { - /* qNan / infinity conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); - } else { - farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status); - } - return farg.ll; -} - -#endif - -static inline uint64_t do_fri(uint64_t arg, int rounding_mode) -{ - CPU_DoubleU farg; - - farg.ll = arg; - - if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN round */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | - POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_quiet_nan(farg.d) || - float64_is_infinity(farg.d))) { - /* qNan / infinity round */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); - } else { - set_float_rounding_mode(rounding_mode, &env->fp_status); - farg.ll = float64_round_to_int(farg.d, &env->fp_status); - /* Restore rounding mode from FPSCR */ - fpscr_set_rounding_mode(); - } - return farg.ll; -} - -uint64_t helper_frin(uint64_t arg) -{ - return do_fri(arg, float_round_nearest_even); -} - -uint64_t helper_friz(uint64_t arg) -{ - return do_fri(arg, float_round_to_zero); -} - -uint64_t helper_frip(uint64_t arg) -{ - return do_fri(arg, float_round_up); -} - -uint64_t helper_frim(uint64_t arg) -{ - return do_fri(arg, float_round_down); -} - -/* fmadd - fmadd. */ -uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) -{ - CPU_DoubleU farg1, farg2, farg3; - - farg1.ll = arg1; - farg2.ll = arg2; - farg3.ll = arg3; - - if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || - (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { - /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d) || - float64_is_signaling_nan(farg3.d))) { - /* sNaN operation */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - /* This is the way the PowerPC specification defines it */ - float128 ft0_128, ft1_128; - - ft0_128 = float64_to_float128(farg1.d, &env->fp_status); - ft1_128 = float64_to_float128(farg2.d, &env->fp_status); - ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); - if (unlikely(float128_is_infinity(ft0_128) && - float64_is_infinity(farg3.d) && - float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { - /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); - } else { - ft1_128 = float64_to_float128(farg3.d, &env->fp_status); - ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); - farg1.d = float128_to_float64(ft0_128, &env->fp_status); - } - } - - return farg1.ll; -} - -/* fmsub - fmsub. */ -uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) -{ - CPU_DoubleU farg1, farg2, farg3; - - farg1.ll = arg1; - farg2.ll = arg2; - farg3.ll = arg3; - - if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || - (float64_is_zero(farg1.d) && - float64_is_infinity(farg2.d)))) { - /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d) || - float64_is_signaling_nan(farg3.d))) { - /* sNaN operation */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - /* This is the way the PowerPC specification defines it */ - float128 ft0_128, ft1_128; - - ft0_128 = float64_to_float128(farg1.d, &env->fp_status); - ft1_128 = float64_to_float128(farg2.d, &env->fp_status); - ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); - if (unlikely(float128_is_infinity(ft0_128) && - float64_is_infinity(farg3.d) && - float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { - /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); - } else { - ft1_128 = float64_to_float128(farg3.d, &env->fp_status); - ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); - farg1.d = float128_to_float64(ft0_128, &env->fp_status); - } - } - return farg1.ll; -} - -/* fnmadd - fnmadd. */ -uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) -{ - CPU_DoubleU farg1, farg2, farg3; - - farg1.ll = arg1; - farg2.ll = arg2; - farg3.ll = arg3; - - if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || - (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { - /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d) || - float64_is_signaling_nan(farg3.d))) { - /* sNaN operation */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - /* This is the way the PowerPC specification defines it */ - float128 ft0_128, ft1_128; - - ft0_128 = float64_to_float128(farg1.d, &env->fp_status); - ft1_128 = float64_to_float128(farg2.d, &env->fp_status); - ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); - if (unlikely(float128_is_infinity(ft0_128) && - float64_is_infinity(farg3.d) && - float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { - /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); - } else { - ft1_128 = float64_to_float128(farg3.d, &env->fp_status); - ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); - farg1.d = float128_to_float64(ft0_128, &env->fp_status); - } - if (likely(!float64_is_any_nan(farg1.d))) { - farg1.d = float64_chs(farg1.d); - } - } - return farg1.ll; -} - -/* fnmsub - fnmsub. */ -uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) -{ - CPU_DoubleU farg1, farg2, farg3; - - farg1.ll = arg1; - farg2.ll = arg2; - farg3.ll = arg3; - - if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || - (float64_is_zero(farg1.d) && - float64_is_infinity(farg2.d)))) { - /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d) || - float64_is_signaling_nan(farg3.d))) { - /* sNaN operation */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - /* This is the way the PowerPC specification defines it */ - float128 ft0_128, ft1_128; - - ft0_128 = float64_to_float128(farg1.d, &env->fp_status); - ft1_128 = float64_to_float128(farg2.d, &env->fp_status); - ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); - if (unlikely(float128_is_infinity(ft0_128) && - float64_is_infinity(farg3.d) && - float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { - /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); - } else { - ft1_128 = float64_to_float128(farg3.d, &env->fp_status); - ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); - farg1.d = float128_to_float64(ft0_128, &env->fp_status); - } - if (likely(!float64_is_any_nan(farg1.d))) { - farg1.d = float64_chs(farg1.d); - } - } - return farg1.ll; -} - -/* frsp - frsp. */ -uint64_t helper_frsp(uint64_t arg) -{ - CPU_DoubleU farg; - float32 f32; - - farg.ll = arg; - - if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN square root */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - f32 = float64_to_float32(farg.d, &env->fp_status); - farg.d = float32_to_float64(f32, &env->fp_status); - - return farg.ll; -} - -/* fsqrt - fsqrt. */ -uint64_t helper_fsqrt(uint64_t arg) -{ - CPU_DoubleU farg; - - farg.ll = arg; - - if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { - /* Square root of a negative nonzero number */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT); - } else { - if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN square root */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - farg.d = float64_sqrt(farg.d, &env->fp_status); - } - return farg.ll; -} - -/* fre - fre. */ -uint64_t helper_fre(uint64_t arg) -{ - CPU_DoubleU farg; - - farg.ll = arg; - - if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN reciprocal */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - farg.d = float64_div(float64_one, farg.d, &env->fp_status); - return farg.d; -} - -/* fres - fres. */ -uint64_t helper_fres(uint64_t arg) -{ - CPU_DoubleU farg; - float32 f32; - - farg.ll = arg; - - if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN reciprocal */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - farg.d = float64_div(float64_one, farg.d, &env->fp_status); - f32 = float64_to_float32(farg.d, &env->fp_status); - farg.d = float32_to_float64(f32, &env->fp_status); - - return farg.ll; -} - -/* frsqrte - frsqrte. */ -uint64_t helper_frsqrte(uint64_t arg) -{ - CPU_DoubleU farg; - float32 f32; - - farg.ll = arg; - - if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { - /* Reciprocal square root of a negative nonzero number */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT); - } else { - if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN reciprocal square root */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } - farg.d = float64_sqrt(farg.d, &env->fp_status); - farg.d = float64_div(float64_one, farg.d, &env->fp_status); - f32 = float64_to_float32(farg.d, &env->fp_status); - farg.d = float32_to_float64(f32, &env->fp_status); - } - return farg.ll; -} - -/* fsel - fsel. */ -uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3) -{ - CPU_DoubleU farg1; - - farg1.ll = arg1; - - if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && - !float64_is_any_nan(farg1.d)) { - return arg2; - } else { - return arg3; - } -} - -void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD) -{ - CPU_DoubleU farg1, farg2; - uint32_t ret = 0; - - farg1.ll = arg1; - farg2.ll = arg2; - - if (unlikely(float64_is_any_nan(farg1.d) || - float64_is_any_nan(farg2.d))) { - ret = 0x01UL; - } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { - ret = 0x08UL; - } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) { - ret = 0x04UL; - } else { - ret = 0x02UL; - } - - env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= ret << FPSCR_FPRF; - env->crf[crfD] = ret; - if (unlikely(ret == 0x01UL - && (float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d)))) { - /* sNaN comparison */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } -} - -void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD) -{ - CPU_DoubleU farg1, farg2; - uint32_t ret = 0; - - farg1.ll = arg1; - farg2.ll = arg2; - - if (unlikely(float64_is_any_nan(farg1.d) || - float64_is_any_nan(farg2.d))) { - ret = 0x01UL; - } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { - ret = 0x08UL; - } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) { - ret = 0x04UL; - } else { - ret = 0x02UL; - } - - env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= ret << FPSCR_FPRF; - env->crf[crfD] = ret; - if (unlikely(ret == 0x01UL)) { - if (float64_is_signaling_nan(farg1.d) || - float64_is_signaling_nan(farg2.d)) { - /* sNaN comparison */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | - POWERPC_EXCP_FP_VXVC); - } else { - /* qNaN comparison */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC); - } - } -} - /*****************************************************************************/ /* PowerPC 601 specific instructions (POWER bridge) */ @@ -3125,623 +2032,6 @@ uint32_t helper_cntlzw32(uint32_t val) return clz32(val); } -/* Single-precision floating-point conversions */ -static inline uint32_t efscfsi(uint32_t val) -{ - CPU_FloatU u; - - u.f = int32_to_float32(val, &env->vec_status); - - return u.l; -} - -static inline uint32_t efscfui(uint32_t val) -{ - CPU_FloatU u; - - u.f = uint32_to_float32(val, &env->vec_status); - - return u.l; -} - -static inline int32_t efsctsi(uint32_t val) -{ - CPU_FloatU u; - - u.l = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_quiet_nan(u.f))) { - return 0; - } - - return float32_to_int32(u.f, &env->vec_status); -} - -static inline uint32_t efsctui(uint32_t val) -{ - CPU_FloatU u; - - u.l = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_quiet_nan(u.f))) { - return 0; - } - - return float32_to_uint32(u.f, &env->vec_status); -} - -static inline uint32_t efsctsiz(uint32_t val) -{ - CPU_FloatU u; - - u.l = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_quiet_nan(u.f))) { - return 0; - } - - return float32_to_int32_round_to_zero(u.f, &env->vec_status); -} - -static inline uint32_t efsctuiz(uint32_t val) -{ - CPU_FloatU u; - - u.l = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_quiet_nan(u.f))) { - return 0; - } - - return float32_to_uint32_round_to_zero(u.f, &env->vec_status); -} - -static inline uint32_t efscfsf(uint32_t val) -{ - CPU_FloatU u; - float32 tmp; - - u.f = int32_to_float32(val, &env->vec_status); - tmp = int64_to_float32(1ULL << 32, &env->vec_status); - u.f = float32_div(u.f, tmp, &env->vec_status); - - return u.l; -} - -static inline uint32_t efscfuf(uint32_t val) -{ - CPU_FloatU u; - float32 tmp; - - u.f = uint32_to_float32(val, &env->vec_status); - tmp = uint64_to_float32(1ULL << 32, &env->vec_status); - u.f = float32_div(u.f, tmp, &env->vec_status); - - return u.l; -} - -static inline uint32_t efsctsf(uint32_t val) -{ - CPU_FloatU u; - float32 tmp; - - u.l = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_quiet_nan(u.f))) { - return 0; - } - tmp = uint64_to_float32(1ULL << 32, &env->vec_status); - u.f = float32_mul(u.f, tmp, &env->vec_status); - - return float32_to_int32(u.f, &env->vec_status); -} - -static inline uint32_t efsctuf(uint32_t val) -{ - CPU_FloatU u; - float32 tmp; - - u.l = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_quiet_nan(u.f))) { - return 0; - } - tmp = uint64_to_float32(1ULL << 32, &env->vec_status); - u.f = float32_mul(u.f, tmp, &env->vec_status); - - return float32_to_uint32(u.f, &env->vec_status); -} - -#define HELPER_SPE_SINGLE_CONV(name) \ - uint32_t helper_e##name(uint32_t val) \ - { \ - return e##name(val); \ - } -/* efscfsi */ -HELPER_SPE_SINGLE_CONV(fscfsi); -/* efscfui */ -HELPER_SPE_SINGLE_CONV(fscfui); -/* efscfuf */ -HELPER_SPE_SINGLE_CONV(fscfuf); -/* efscfsf */ -HELPER_SPE_SINGLE_CONV(fscfsf); -/* efsctsi */ -HELPER_SPE_SINGLE_CONV(fsctsi); -/* efsctui */ -HELPER_SPE_SINGLE_CONV(fsctui); -/* efsctsiz */ -HELPER_SPE_SINGLE_CONV(fsctsiz); -/* efsctuiz */ -HELPER_SPE_SINGLE_CONV(fsctuiz); -/* efsctsf */ -HELPER_SPE_SINGLE_CONV(fsctsf); -/* efsctuf */ -HELPER_SPE_SINGLE_CONV(fsctuf); - -#define HELPER_SPE_VECTOR_CONV(name) \ - uint64_t helper_ev##name(uint64_t val) \ - { \ - return ((uint64_t)e##name(val >> 32) << 32) | \ - (uint64_t)e##name(val); \ - } -/* evfscfsi */ -HELPER_SPE_VECTOR_CONV(fscfsi); -/* evfscfui */ -HELPER_SPE_VECTOR_CONV(fscfui); -/* evfscfuf */ -HELPER_SPE_VECTOR_CONV(fscfuf); -/* evfscfsf */ -HELPER_SPE_VECTOR_CONV(fscfsf); -/* evfsctsi */ -HELPER_SPE_VECTOR_CONV(fsctsi); -/* evfsctui */ -HELPER_SPE_VECTOR_CONV(fsctui); -/* evfsctsiz */ -HELPER_SPE_VECTOR_CONV(fsctsiz); -/* evfsctuiz */ -HELPER_SPE_VECTOR_CONV(fsctuiz); -/* evfsctsf */ -HELPER_SPE_VECTOR_CONV(fsctsf); -/* evfsctuf */ -HELPER_SPE_VECTOR_CONV(fsctuf); - -/* Single-precision floating-point arithmetic */ -static inline uint32_t efsadd(uint32_t op1, uint32_t op2) -{ - CPU_FloatU u1, u2; - - u1.l = op1; - u2.l = op2; - u1.f = float32_add(u1.f, u2.f, &env->vec_status); - return u1.l; -} - -static inline uint32_t efssub(uint32_t op1, uint32_t op2) -{ - CPU_FloatU u1, u2; - - u1.l = op1; - u2.l = op2; - u1.f = float32_sub(u1.f, u2.f, &env->vec_status); - return u1.l; -} - -static inline uint32_t efsmul(uint32_t op1, uint32_t op2) -{ - CPU_FloatU u1, u2; - - u1.l = op1; - u2.l = op2; - u1.f = float32_mul(u1.f, u2.f, &env->vec_status); - return u1.l; -} - -static inline uint32_t efsdiv(uint32_t op1, uint32_t op2) -{ - CPU_FloatU u1, u2; - - u1.l = op1; - u2.l = op2; - u1.f = float32_div(u1.f, u2.f, &env->vec_status); - return u1.l; -} - -#define HELPER_SPE_SINGLE_ARITH(name) \ - uint32_t helper_e##name(uint32_t op1, uint32_t op2) \ - { \ - return e##name(op1, op2); \ - } -/* efsadd */ -HELPER_SPE_SINGLE_ARITH(fsadd); -/* efssub */ -HELPER_SPE_SINGLE_ARITH(fssub); -/* efsmul */ -HELPER_SPE_SINGLE_ARITH(fsmul); -/* efsdiv */ -HELPER_SPE_SINGLE_ARITH(fsdiv); - -#define HELPER_SPE_VECTOR_ARITH(name) \ - uint64_t helper_ev##name(uint64_t op1, uint64_t op2) \ - { \ - return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \ - (uint64_t)e##name(op1, op2); \ - } -/* evfsadd */ -HELPER_SPE_VECTOR_ARITH(fsadd); -/* evfssub */ -HELPER_SPE_VECTOR_ARITH(fssub); -/* evfsmul */ -HELPER_SPE_VECTOR_ARITH(fsmul); -/* evfsdiv */ -HELPER_SPE_VECTOR_ARITH(fsdiv); - -/* Single-precision floating-point comparisons */ -static inline uint32_t efscmplt(uint32_t op1, uint32_t op2) -{ - CPU_FloatU u1, u2; - - u1.l = op1; - u2.l = op2; - return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0; -} - -static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2) -{ - CPU_FloatU u1, u2; - - u1.l = op1; - u2.l = op2; - return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4; -} - -static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2) -{ - CPU_FloatU u1, u2; - - u1.l = op1; - u2.l = op2; - return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0; -} - -static inline uint32_t efststlt(uint32_t op1, uint32_t op2) -{ - /* XXX: TODO: ignore special values (NaN, infinites, ...) */ - return efscmplt(op1, op2); -} - -static inline uint32_t efststgt(uint32_t op1, uint32_t op2) -{ - /* XXX: TODO: ignore special values (NaN, infinites, ...) */ - return efscmpgt(op1, op2); -} - -static inline uint32_t efststeq(uint32_t op1, uint32_t op2) -{ - /* XXX: TODO: ignore special values (NaN, infinites, ...) */ - return efscmpeq(op1, op2); -} - -#define HELPER_SINGLE_SPE_CMP(name) \ - uint32_t helper_e##name(uint32_t op1, uint32_t op2) \ - { \ - return e##name(op1, op2) << 2; \ - } -/* efststlt */ -HELPER_SINGLE_SPE_CMP(fststlt); -/* efststgt */ -HELPER_SINGLE_SPE_CMP(fststgt); -/* efststeq */ -HELPER_SINGLE_SPE_CMP(fststeq); -/* efscmplt */ -HELPER_SINGLE_SPE_CMP(fscmplt); -/* efscmpgt */ -HELPER_SINGLE_SPE_CMP(fscmpgt); -/* efscmpeq */ -HELPER_SINGLE_SPE_CMP(fscmpeq); - -static inline uint32_t evcmp_merge(int t0, int t1) -{ - return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1); -} - -#define HELPER_VECTOR_SPE_CMP(name) \ - uint32_t helper_ev##name(uint64_t op1, uint64_t op2) \ - { \ - return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \ - } -/* evfststlt */ -HELPER_VECTOR_SPE_CMP(fststlt); -/* evfststgt */ -HELPER_VECTOR_SPE_CMP(fststgt); -/* evfststeq */ -HELPER_VECTOR_SPE_CMP(fststeq); -/* evfscmplt */ -HELPER_VECTOR_SPE_CMP(fscmplt); -/* evfscmpgt */ -HELPER_VECTOR_SPE_CMP(fscmpgt); -/* evfscmpeq */ -HELPER_VECTOR_SPE_CMP(fscmpeq); - -/* Double-precision floating-point conversion */ -uint64_t helper_efdcfsi(uint32_t val) -{ - CPU_DoubleU u; - - u.d = int32_to_float64(val, &env->vec_status); - - return u.ll; -} - -uint64_t helper_efdcfsid(uint64_t val) -{ - CPU_DoubleU u; - - u.d = int64_to_float64(val, &env->vec_status); - - return u.ll; -} - -uint64_t helper_efdcfui(uint32_t val) -{ - CPU_DoubleU u; - - u.d = uint32_to_float64(val, &env->vec_status); - - return u.ll; -} - -uint64_t helper_efdcfuid(uint64_t val) -{ - CPU_DoubleU u; - - u.d = uint64_to_float64(val, &env->vec_status); - - return u.ll; -} - -uint32_t helper_efdctsi(uint64_t val) -{ - CPU_DoubleU u; - - u.ll = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_any_nan(u.d))) { - return 0; - } - - return float64_to_int32(u.d, &env->vec_status); -} - -uint32_t helper_efdctui(uint64_t val) -{ - CPU_DoubleU u; - - u.ll = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_any_nan(u.d))) { - return 0; - } - - return float64_to_uint32(u.d, &env->vec_status); -} - -uint32_t helper_efdctsiz(uint64_t val) -{ - CPU_DoubleU u; - - u.ll = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_any_nan(u.d))) { - return 0; - } - - return float64_to_int32_round_to_zero(u.d, &env->vec_status); -} - -uint64_t helper_efdctsidz(uint64_t val) -{ - CPU_DoubleU u; - - u.ll = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_any_nan(u.d))) { - return 0; - } - - return float64_to_int64_round_to_zero(u.d, &env->vec_status); -} - -uint32_t helper_efdctuiz(uint64_t val) -{ - CPU_DoubleU u; - - u.ll = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_any_nan(u.d))) { - return 0; - } - - return float64_to_uint32_round_to_zero(u.d, &env->vec_status); -} - -uint64_t helper_efdctuidz(uint64_t val) -{ - CPU_DoubleU u; - - u.ll = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_any_nan(u.d))) { - return 0; - } - - return float64_to_uint64_round_to_zero(u.d, &env->vec_status); -} - -uint64_t helper_efdcfsf(uint32_t val) -{ - CPU_DoubleU u; - float64 tmp; - - u.d = int32_to_float64(val, &env->vec_status); - tmp = int64_to_float64(1ULL << 32, &env->vec_status); - u.d = float64_div(u.d, tmp, &env->vec_status); - - return u.ll; -} - -uint64_t helper_efdcfuf(uint32_t val) -{ - CPU_DoubleU u; - float64 tmp; - - u.d = uint32_to_float64(val, &env->vec_status); - tmp = int64_to_float64(1ULL << 32, &env->vec_status); - u.d = float64_div(u.d, tmp, &env->vec_status); - - return u.ll; -} - -uint32_t helper_efdctsf(uint64_t val) -{ - CPU_DoubleU u; - float64 tmp; - - u.ll = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_any_nan(u.d))) { - return 0; - } - tmp = uint64_to_float64(1ULL << 32, &env->vec_status); - u.d = float64_mul(u.d, tmp, &env->vec_status); - - return float64_to_int32(u.d, &env->vec_status); -} - -uint32_t helper_efdctuf(uint64_t val) -{ - CPU_DoubleU u; - float64 tmp; - - u.ll = val; - /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_any_nan(u.d))) { - return 0; - } - tmp = uint64_to_float64(1ULL << 32, &env->vec_status); - u.d = float64_mul(u.d, tmp, &env->vec_status); - - return float64_to_uint32(u.d, &env->vec_status); -} - -uint32_t helper_efscfd(uint64_t val) -{ - CPU_DoubleU u1; - CPU_FloatU u2; - - u1.ll = val; - u2.f = float64_to_float32(u1.d, &env->vec_status); - - return u2.l; -} - -uint64_t helper_efdcfs(uint32_t val) -{ - CPU_DoubleU u2; - CPU_FloatU u1; - - u1.l = val; - u2.d = float32_to_float64(u1.f, &env->vec_status); - - return u2.ll; -} - -/* Double precision fixed-point arithmetic */ -uint64_t helper_efdadd(uint64_t op1, uint64_t op2) -{ - CPU_DoubleU u1, u2; - - u1.ll = op1; - u2.ll = op2; - u1.d = float64_add(u1.d, u2.d, &env->vec_status); - return u1.ll; -} - -uint64_t helper_efdsub(uint64_t op1, uint64_t op2) -{ - CPU_DoubleU u1, u2; - - u1.ll = op1; - u2.ll = op2; - u1.d = float64_sub(u1.d, u2.d, &env->vec_status); - return u1.ll; -} - -uint64_t helper_efdmul(uint64_t op1, uint64_t op2) -{ - CPU_DoubleU u1, u2; - - u1.ll = op1; - u2.ll = op2; - u1.d = float64_mul(u1.d, u2.d, &env->vec_status); - return u1.ll; -} - -uint64_t helper_efddiv(uint64_t op1, uint64_t op2) -{ - CPU_DoubleU u1, u2; - - u1.ll = op1; - u2.ll = op2; - u1.d = float64_div(u1.d, u2.d, &env->vec_status); - return u1.ll; -} - -/* Double precision floating point helpers */ -uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2) -{ - CPU_DoubleU u1, u2; - - u1.ll = op1; - u2.ll = op2; - return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0; -} - -uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2) -{ - CPU_DoubleU u1, u2; - - u1.ll = op1; - u2.ll = op2; - return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4; -} - -uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2) -{ - CPU_DoubleU u1, u2; - - u1.ll = op1; - u2.ll = op2; - return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0; -} - -uint32_t helper_efdcmplt(uint64_t op1, uint64_t op2) -{ - /* XXX: TODO: test special values (NaN, infinites, ...) */ - return helper_efdtstlt(op1, op2); -} - -uint32_t helper_efdcmpgt(uint64_t op1, uint64_t op2) -{ - /* XXX: TODO: test special values (NaN, infinites, ...) */ - return helper_efdtstgt(op1, op2); -} - -uint32_t helper_efdcmpeq(uint64_t op1, uint64_t op2) -{ - /* XXX: TODO: test special values (NaN, infinites, ...) */ - return helper_efdtsteq(op1, op2); -} - /*****************************************************************************/ /* Softmmu support */ #if !defined(CONFIG_USER_ONLY) From 8e70394950ed55dd7f0a5f9b5f831cf70089d0df Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:27 +0000 Subject: [PATCH 07/72] ppc: Avoid AREG0 for FPU and SPE helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an explicit CPUPPCState parameter instead of relying on AREG0. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 1 - target-ppc/fpu_helper.c | 350 ++++++++++++++++++++------------------- target-ppc/helper.h | 204 +++++++++++------------ target-ppc/translate.c | 113 +++++++------ 4 files changed, 346 insertions(+), 322 deletions(-) diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index dde916c685..5bea9c3377 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -5,5 +5,4 @@ obj-y += op_helper.o helper.o obj-y += excp_helper.o obj-y += fpu_helper.o -$(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c index be965d106d..d90636fad0 100644 --- a/target-ppc/fpu_helper.c +++ b/target-ppc/fpu_helper.c @@ -17,12 +17,11 @@ * License along with this library; if not, see . */ #include "cpu.h" -#include "dyngen-exec.h" #include "helper.h" /*****************************************************************************/ /* Floating point operations helpers */ -uint64_t helper_float32_to_float64(uint32_t arg) +uint64_t helper_float32_to_float64(CPUPPCState *env, uint32_t arg) { CPU_FloatU f; CPU_DoubleU d; @@ -32,7 +31,7 @@ uint64_t helper_float32_to_float64(uint32_t arg) return d.ll; } -uint32_t helper_float64_to_float32(uint64_t arg) +uint32_t helper_float64_to_float32(CPUPPCState *env, uint64_t arg) { CPU_FloatU f; CPU_DoubleU d; @@ -51,7 +50,7 @@ static inline int isden(float64 d) return ((u.ll >> 52) & 0x7FF) == 0; } -uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf) +uint32_t helper_compute_fprf(CPUPPCState *env, uint64_t arg, uint32_t set_fprf) { CPU_DoubleU farg; int isneg; @@ -107,7 +106,7 @@ uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf) } /* Floating-point invalid operations exception */ -static inline uint64_t fload_invalid_op_excp(int op) +static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op) { uint64_t ret = 0; int ve; @@ -190,7 +189,7 @@ static inline uint64_t fload_invalid_op_excp(int op) return ret; } -static inline void float_zero_divide_excp(void) +static inline void float_zero_divide_excp(CPUPPCState *env) { env->fpscr |= 1 << FPSCR_ZX; env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); @@ -206,7 +205,7 @@ static inline void float_zero_divide_excp(void) } } -static inline void float_overflow_excp(void) +static inline void float_overflow_excp(CPUPPCState *env) { env->fpscr |= 1 << FPSCR_OX; /* Update the floating-point exception summary */ @@ -224,7 +223,7 @@ static inline void float_overflow_excp(void) } } -static inline void float_underflow_excp(void) +static inline void float_underflow_excp(CPUPPCState *env) { env->fpscr |= 1 << FPSCR_UX; /* Update the floating-point exception summary */ @@ -239,7 +238,7 @@ static inline void float_underflow_excp(void) } } -static inline void float_inexact_excp(void) +static inline void float_inexact_excp(CPUPPCState *env) { env->fpscr |= 1 << FPSCR_XX; /* Update the floating-point exception summary */ @@ -253,7 +252,7 @@ static inline void float_inexact_excp(void) } } -static inline void fpscr_set_rounding_mode(void) +static inline void fpscr_set_rounding_mode(CPUPPCState *env) { int rnd_type; @@ -280,7 +279,7 @@ static inline void fpscr_set_rounding_mode(void) set_float_rounding_mode(rnd_type, &env->fp_status); } -void helper_fpscr_clrbit(uint32_t bit) +void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit) { int prev; @@ -290,7 +289,7 @@ void helper_fpscr_clrbit(uint32_t bit) switch (bit) { case FPSCR_RN1: case FPSCR_RN: - fpscr_set_rounding_mode(); + fpscr_set_rounding_mode(env); break; default: break; @@ -298,7 +297,7 @@ void helper_fpscr_clrbit(uint32_t bit) } } -void helper_fpscr_setbit(uint32_t bit) +void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit) { int prev; @@ -414,7 +413,7 @@ void helper_fpscr_setbit(uint32_t bit) break; case FPSCR_RN1: case FPSCR_RN: - fpscr_set_rounding_mode(); + fpscr_set_rounding_mode(env); break; default: break; @@ -428,7 +427,7 @@ void helper_fpscr_setbit(uint32_t bit) } } -void helper_store_fpscr(uint64_t arg, uint32_t mask) +void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) { /* * We use only the 32 LSB of the incoming fpr @@ -460,10 +459,10 @@ void helper_store_fpscr(uint64_t arg, uint32_t mask) } else { env->fpscr &= ~(1 << FPSCR_FEX); } - fpscr_set_rounding_mode(); + fpscr_set_rounding_mode(env); } -void helper_float_check_status(void) +void helper_float_check_status(CPUPPCState *env) { if (env->exception_index == POWERPC_EXCP_PROGRAM && (env->error_code & POWERPC_EXCP_FP)) { @@ -475,24 +474,24 @@ void helper_float_check_status(void) } else { int status = get_float_exception_flags(&env->fp_status); if (status & float_flag_divbyzero) { - float_zero_divide_excp(); + float_zero_divide_excp(env); } else if (status & float_flag_overflow) { - float_overflow_excp(); + float_overflow_excp(env); } else if (status & float_flag_underflow) { - float_underflow_excp(); + float_underflow_excp(env); } else if (status & float_flag_inexact) { - float_inexact_excp(); + float_inexact_excp(env); } } } -void helper_reset_fpstatus(void) +void helper_reset_fpstatus(CPUPPCState *env) { set_float_exception_flags(0, &env->fp_status); } /* fadd - fadd. */ -uint64_t helper_fadd(uint64_t arg1, uint64_t arg2) +uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2) { CPU_DoubleU farg1, farg2; @@ -502,12 +501,12 @@ uint64_t helper_fadd(uint64_t arg1, uint64_t arg2) if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) { /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI); } else { if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d))) { /* sNaN addition */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status); } @@ -516,7 +515,7 @@ uint64_t helper_fadd(uint64_t arg1, uint64_t arg2) } /* fsub - fsub. */ -uint64_t helper_fsub(uint64_t arg1, uint64_t arg2) +uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2) { CPU_DoubleU farg1, farg2; @@ -526,12 +525,12 @@ uint64_t helper_fsub(uint64_t arg1, uint64_t arg2) if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) { /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI); } else { if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d))) { /* sNaN subtraction */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status); } @@ -540,7 +539,7 @@ uint64_t helper_fsub(uint64_t arg1, uint64_t arg2) } /* fmul - fmul. */ -uint64_t helper_fmul(uint64_t arg1, uint64_t arg2) +uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2) { CPU_DoubleU farg1, farg2; @@ -550,12 +549,12 @@ uint64_t helper_fmul(uint64_t arg1, uint64_t arg2) if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ); } else { if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d))) { /* sNaN multiplication */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); } @@ -564,7 +563,7 @@ uint64_t helper_fmul(uint64_t arg1, uint64_t arg2) } /* fdiv - fdiv. */ -uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2) +uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2) { CPU_DoubleU farg1, farg2; @@ -574,15 +573,15 @@ uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2) if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) { /* Division of infinity by infinity */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI); } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) { /* Division of zero by zero */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ); } else { if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d))) { /* sNaN division */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status); } @@ -591,7 +590,7 @@ uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2) } /* fabs */ -uint64_t helper_fabs(uint64_t arg) +uint64_t helper_fabs(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; @@ -601,7 +600,7 @@ uint64_t helper_fabs(uint64_t arg) } /* fnabs */ -uint64_t helper_fnabs(uint64_t arg) +uint64_t helper_fnabs(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; @@ -612,7 +611,7 @@ uint64_t helper_fnabs(uint64_t arg) } /* fneg */ -uint64_t helper_fneg(uint64_t arg) +uint64_t helper_fneg(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; @@ -622,7 +621,7 @@ uint64_t helper_fneg(uint64_t arg) } /* fctiw - fctiw. */ -uint64_t helper_fctiw(uint64_t arg) +uint64_t helper_fctiw(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; @@ -630,12 +629,12 @@ uint64_t helper_fctiw(uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { /* qNan / infinity conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI); } else { farg.ll = float64_to_int32(farg.d, &env->fp_status); /* XXX: higher bits are not supposed to be significant. @@ -647,7 +646,7 @@ uint64_t helper_fctiw(uint64_t arg) } /* fctiwz - fctiwz. */ -uint64_t helper_fctiwz(uint64_t arg) +uint64_t helper_fctiwz(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; @@ -655,12 +654,12 @@ uint64_t helper_fctiwz(uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { /* qNan / infinity conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI); } else { farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status); /* XXX: higher bits are not supposed to be significant. @@ -673,7 +672,7 @@ uint64_t helper_fctiwz(uint64_t arg) #if defined(TARGET_PPC64) /* fcfid - fcfid. */ -uint64_t helper_fcfid(uint64_t arg) +uint64_t helper_fcfid(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; @@ -682,7 +681,7 @@ uint64_t helper_fcfid(uint64_t arg) } /* fctid - fctid. */ -uint64_t helper_fctid(uint64_t arg) +uint64_t helper_fctid(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; @@ -690,12 +689,12 @@ uint64_t helper_fctid(uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { /* qNan / infinity conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI); } else { farg.ll = float64_to_int64(farg.d, &env->fp_status); } @@ -703,7 +702,7 @@ uint64_t helper_fctid(uint64_t arg) } /* fctidz - fctidz. */ -uint64_t helper_fctidz(uint64_t arg) +uint64_t helper_fctidz(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; @@ -711,12 +710,12 @@ uint64_t helper_fctidz(uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { /* qNan / infinity conversion */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI); } else { farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status); } @@ -725,7 +724,8 @@ uint64_t helper_fctidz(uint64_t arg) #endif -static inline uint64_t do_fri(uint64_t arg, int rounding_mode) +static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, + int rounding_mode) { CPU_DoubleU farg; @@ -733,43 +733,44 @@ static inline uint64_t do_fri(uint64_t arg, int rounding_mode) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN round */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { /* qNan / infinity round */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI); } else { set_float_rounding_mode(rounding_mode, &env->fp_status); farg.ll = float64_round_to_int(farg.d, &env->fp_status); /* Restore rounding mode from FPSCR */ - fpscr_set_rounding_mode(); + fpscr_set_rounding_mode(env); } return farg.ll; } -uint64_t helper_frin(uint64_t arg) +uint64_t helper_frin(CPUPPCState *env, uint64_t arg) { - return do_fri(arg, float_round_nearest_even); + return do_fri(env, arg, float_round_nearest_even); } -uint64_t helper_friz(uint64_t arg) +uint64_t helper_friz(CPUPPCState *env, uint64_t arg) { - return do_fri(arg, float_round_to_zero); + return do_fri(env, arg, float_round_to_zero); } -uint64_t helper_frip(uint64_t arg) +uint64_t helper_frip(CPUPPCState *env, uint64_t arg) { - return do_fri(arg, float_round_up); + return do_fri(env, arg, float_round_up); } -uint64_t helper_frim(uint64_t arg) +uint64_t helper_frim(CPUPPCState *env, uint64_t arg) { - return do_fri(arg, float_round_down); + return do_fri(env, arg, float_round_down); } /* fmadd - fmadd. */ -uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) +uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2, + uint64_t arg3) { CPU_DoubleU farg1, farg2, farg3; @@ -780,13 +781,13 @@ uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ); } else { if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d) || float64_is_signaling_nan(farg3.d))) { /* sNaN operation */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -798,7 +799,7 @@ uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) float64_is_infinity(farg3.d) && float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI); } else { ft1_128 = float64_to_float128(farg3.d, &env->fp_status); ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); @@ -810,7 +811,8 @@ uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) } /* fmsub - fmsub. */ -uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) +uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2, + uint64_t arg3) { CPU_DoubleU farg1, farg2, farg3; @@ -822,13 +824,13 @@ uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ); } else { if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d) || float64_is_signaling_nan(farg3.d))) { /* sNaN operation */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -840,7 +842,7 @@ uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) float64_is_infinity(farg3.d) && float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI); } else { ft1_128 = float64_to_float128(farg3.d, &env->fp_status); ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); @@ -851,7 +853,8 @@ uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) } /* fnmadd - fnmadd. */ -uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) +uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2, + uint64_t arg3) { CPU_DoubleU farg1, farg2, farg3; @@ -862,13 +865,13 @@ uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ); } else { if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d) || float64_is_signaling_nan(farg3.d))) { /* sNaN operation */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -880,7 +883,7 @@ uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) float64_is_infinity(farg3.d) && float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI); } else { ft1_128 = float64_to_float128(farg3.d, &env->fp_status); ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); @@ -894,7 +897,8 @@ uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3) } /* fnmsub - fnmsub. */ -uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) +uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2, + uint64_t arg3) { CPU_DoubleU farg1, farg2, farg3; @@ -906,13 +910,13 @@ uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { /* Multiplication of zero by infinity */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ); } else { if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d) || float64_is_signaling_nan(farg3.d))) { /* sNaN operation */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -924,7 +928,7 @@ uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) float64_is_infinity(farg3.d) && float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { /* Magnitude subtraction of infinities */ - farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI); } else { ft1_128 = float64_to_float128(farg3.d, &env->fp_status); ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); @@ -938,7 +942,7 @@ uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3) } /* frsp - frsp. */ -uint64_t helper_frsp(uint64_t arg) +uint64_t helper_frsp(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; float32 f32; @@ -947,7 +951,7 @@ uint64_t helper_frsp(uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN square root */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } f32 = float64_to_float32(farg.d, &env->fp_status); farg.d = float32_to_float64(f32, &env->fp_status); @@ -956,7 +960,7 @@ uint64_t helper_frsp(uint64_t arg) } /* fsqrt - fsqrt. */ -uint64_t helper_fsqrt(uint64_t arg) +uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; @@ -964,11 +968,11 @@ uint64_t helper_fsqrt(uint64_t arg) if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { /* Square root of a negative nonzero number */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT); + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT); } else { if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN square root */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } farg.d = float64_sqrt(farg.d, &env->fp_status); } @@ -976,7 +980,7 @@ uint64_t helper_fsqrt(uint64_t arg) } /* fre - fre. */ -uint64_t helper_fre(uint64_t arg) +uint64_t helper_fre(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; @@ -984,14 +988,14 @@ uint64_t helper_fre(uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN reciprocal */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } farg.d = float64_div(float64_one, farg.d, &env->fp_status); return farg.d; } /* fres - fres. */ -uint64_t helper_fres(uint64_t arg) +uint64_t helper_fres(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; float32 f32; @@ -1000,7 +1004,7 @@ uint64_t helper_fres(uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN reciprocal */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } farg.d = float64_div(float64_one, farg.d, &env->fp_status); f32 = float64_to_float32(farg.d, &env->fp_status); @@ -1010,7 +1014,7 @@ uint64_t helper_fres(uint64_t arg) } /* frsqrte - frsqrte. */ -uint64_t helper_frsqrte(uint64_t arg) +uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; float32 f32; @@ -1019,11 +1023,11 @@ uint64_t helper_frsqrte(uint64_t arg) if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { /* Reciprocal square root of a negative nonzero number */ - farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT); + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT); } else { if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN reciprocal square root */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } farg.d = float64_sqrt(farg.d, &env->fp_status); farg.d = float64_div(float64_one, farg.d, &env->fp_status); @@ -1034,7 +1038,8 @@ uint64_t helper_frsqrte(uint64_t arg) } /* fsel - fsel. */ -uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3) +uint64_t helper_fsel(CPUPPCState *env, uint64_t arg1, uint64_t arg2, + uint64_t arg3) { CPU_DoubleU farg1; @@ -1048,7 +1053,8 @@ uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3) } } -void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD) +void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2, + uint32_t crfD) { CPU_DoubleU farg1, farg2; uint32_t ret = 0; @@ -1074,11 +1080,12 @@ void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD) && (float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d)))) { /* sNaN comparison */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); } } -void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD) +void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2, + uint32_t crfD) { CPU_DoubleU farg1, farg2; uint32_t ret = 0; @@ -1104,17 +1111,17 @@ void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD) if (float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d)) { /* sNaN comparison */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXVC); } else { /* qNaN comparison */ - fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC); + fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC); } } } /* Single-precision floating-point conversions */ -static inline uint32_t efscfsi(uint32_t val) +static inline uint32_t efscfsi(CPUPPCState *env, uint32_t val) { CPU_FloatU u; @@ -1123,7 +1130,7 @@ static inline uint32_t efscfsi(uint32_t val) return u.l; } -static inline uint32_t efscfui(uint32_t val) +static inline uint32_t efscfui(CPUPPCState *env, uint32_t val) { CPU_FloatU u; @@ -1132,7 +1139,7 @@ static inline uint32_t efscfui(uint32_t val) return u.l; } -static inline int32_t efsctsi(uint32_t val) +static inline int32_t efsctsi(CPUPPCState *env, uint32_t val) { CPU_FloatU u; @@ -1145,7 +1152,7 @@ static inline int32_t efsctsi(uint32_t val) return float32_to_int32(u.f, &env->vec_status); } -static inline uint32_t efsctui(uint32_t val) +static inline uint32_t efsctui(CPUPPCState *env, uint32_t val) { CPU_FloatU u; @@ -1158,7 +1165,7 @@ static inline uint32_t efsctui(uint32_t val) return float32_to_uint32(u.f, &env->vec_status); } -static inline uint32_t efsctsiz(uint32_t val) +static inline uint32_t efsctsiz(CPUPPCState *env, uint32_t val) { CPU_FloatU u; @@ -1171,7 +1178,7 @@ static inline uint32_t efsctsiz(uint32_t val) return float32_to_int32_round_to_zero(u.f, &env->vec_status); } -static inline uint32_t efsctuiz(uint32_t val) +static inline uint32_t efsctuiz(CPUPPCState *env, uint32_t val) { CPU_FloatU u; @@ -1184,7 +1191,7 @@ static inline uint32_t efsctuiz(uint32_t val) return float32_to_uint32_round_to_zero(u.f, &env->vec_status); } -static inline uint32_t efscfsf(uint32_t val) +static inline uint32_t efscfsf(CPUPPCState *env, uint32_t val) { CPU_FloatU u; float32 tmp; @@ -1196,7 +1203,7 @@ static inline uint32_t efscfsf(uint32_t val) return u.l; } -static inline uint32_t efscfuf(uint32_t val) +static inline uint32_t efscfuf(CPUPPCState *env, uint32_t val) { CPU_FloatU u; float32 tmp; @@ -1208,7 +1215,7 @@ static inline uint32_t efscfuf(uint32_t val) return u.l; } -static inline uint32_t efsctsf(uint32_t val) +static inline uint32_t efsctsf(CPUPPCState *env, uint32_t val) { CPU_FloatU u; float32 tmp; @@ -1224,7 +1231,7 @@ static inline uint32_t efsctsf(uint32_t val) return float32_to_int32(u.f, &env->vec_status); } -static inline uint32_t efsctuf(uint32_t val) +static inline uint32_t efsctuf(CPUPPCState *env, uint32_t val) { CPU_FloatU u; float32 tmp; @@ -1240,10 +1247,10 @@ static inline uint32_t efsctuf(uint32_t val) return float32_to_uint32(u.f, &env->vec_status); } -#define HELPER_SPE_SINGLE_CONV(name) \ - uint32_t helper_e##name(uint32_t val) \ - { \ - return e##name(val); \ +#define HELPER_SPE_SINGLE_CONV(name) \ + uint32_t helper_e##name(CPUPPCState *env, uint32_t val) \ + { \ + return e##name(env, val); \ } /* efscfsi */ HELPER_SPE_SINGLE_CONV(fscfsi); @@ -1266,11 +1273,11 @@ HELPER_SPE_SINGLE_CONV(fsctsf); /* efsctuf */ HELPER_SPE_SINGLE_CONV(fsctuf); -#define HELPER_SPE_VECTOR_CONV(name) \ - uint64_t helper_ev##name(uint64_t val) \ - { \ - return ((uint64_t)e##name(val >> 32) << 32) | \ - (uint64_t)e##name(val); \ +#define HELPER_SPE_VECTOR_CONV(name) \ + uint64_t helper_ev##name(CPUPPCState *env, uint64_t val) \ + { \ + return ((uint64_t)e##name(env, val >> 32) << 32) | \ + (uint64_t)e##name(env, val); \ } /* evfscfsi */ HELPER_SPE_VECTOR_CONV(fscfsi); @@ -1294,7 +1301,7 @@ HELPER_SPE_VECTOR_CONV(fsctsf); HELPER_SPE_VECTOR_CONV(fsctuf); /* Single-precision floating-point arithmetic */ -static inline uint32_t efsadd(uint32_t op1, uint32_t op2) +static inline uint32_t efsadd(CPUPPCState *env, uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; @@ -1304,7 +1311,7 @@ static inline uint32_t efsadd(uint32_t op1, uint32_t op2) return u1.l; } -static inline uint32_t efssub(uint32_t op1, uint32_t op2) +static inline uint32_t efssub(CPUPPCState *env, uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; @@ -1314,7 +1321,7 @@ static inline uint32_t efssub(uint32_t op1, uint32_t op2) return u1.l; } -static inline uint32_t efsmul(uint32_t op1, uint32_t op2) +static inline uint32_t efsmul(CPUPPCState *env, uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; @@ -1324,7 +1331,7 @@ static inline uint32_t efsmul(uint32_t op1, uint32_t op2) return u1.l; } -static inline uint32_t efsdiv(uint32_t op1, uint32_t op2) +static inline uint32_t efsdiv(CPUPPCState *env, uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; @@ -1334,10 +1341,10 @@ static inline uint32_t efsdiv(uint32_t op1, uint32_t op2) return u1.l; } -#define HELPER_SPE_SINGLE_ARITH(name) \ - uint32_t helper_e##name(uint32_t op1, uint32_t op2) \ - { \ - return e##name(op1, op2); \ +#define HELPER_SPE_SINGLE_ARITH(name) \ + uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \ + { \ + return e##name(env, op1, op2); \ } /* efsadd */ HELPER_SPE_SINGLE_ARITH(fsadd); @@ -1349,10 +1356,10 @@ HELPER_SPE_SINGLE_ARITH(fsmul); HELPER_SPE_SINGLE_ARITH(fsdiv); #define HELPER_SPE_VECTOR_ARITH(name) \ - uint64_t helper_ev##name(uint64_t op1, uint64_t op2) \ + uint64_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \ { \ - return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \ - (uint64_t)e##name(op1, op2); \ + return ((uint64_t)e##name(env, op1 >> 32, op2 >> 32) << 32) | \ + (uint64_t)e##name(env, op1, op2); \ } /* evfsadd */ HELPER_SPE_VECTOR_ARITH(fsadd); @@ -1364,7 +1371,7 @@ HELPER_SPE_VECTOR_ARITH(fsmul); HELPER_SPE_VECTOR_ARITH(fsdiv); /* Single-precision floating-point comparisons */ -static inline uint32_t efscmplt(uint32_t op1, uint32_t op2) +static inline uint32_t efscmplt(CPUPPCState *env, uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; @@ -1373,7 +1380,7 @@ static inline uint32_t efscmplt(uint32_t op1, uint32_t op2) return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0; } -static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2) +static inline uint32_t efscmpgt(CPUPPCState *env, uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; @@ -1382,7 +1389,7 @@ static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2) return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4; } -static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2) +static inline uint32_t efscmpeq(CPUPPCState *env, uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; @@ -1391,28 +1398,28 @@ static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2) return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0; } -static inline uint32_t efststlt(uint32_t op1, uint32_t op2) +static inline uint32_t efststlt(CPUPPCState *env, uint32_t op1, uint32_t op2) { /* XXX: TODO: ignore special values (NaN, infinites, ...) */ - return efscmplt(op1, op2); + return efscmplt(env, op1, op2); } -static inline uint32_t efststgt(uint32_t op1, uint32_t op2) +static inline uint32_t efststgt(CPUPPCState *env, uint32_t op1, uint32_t op2) { /* XXX: TODO: ignore special values (NaN, infinites, ...) */ - return efscmpgt(op1, op2); + return efscmpgt(env, op1, op2); } -static inline uint32_t efststeq(uint32_t op1, uint32_t op2) +static inline uint32_t efststeq(CPUPPCState *env, uint32_t op1, uint32_t op2) { /* XXX: TODO: ignore special values (NaN, infinites, ...) */ - return efscmpeq(op1, op2); + return efscmpeq(env, op1, op2); } -#define HELPER_SINGLE_SPE_CMP(name) \ - uint32_t helper_e##name(uint32_t op1, uint32_t op2) \ - { \ - return e##name(op1, op2) << 2; \ +#define HELPER_SINGLE_SPE_CMP(name) \ + uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \ + { \ + return e##name(env, op1, op2) << 2; \ } /* efststlt */ HELPER_SINGLE_SPE_CMP(fststlt); @@ -1433,9 +1440,10 @@ static inline uint32_t evcmp_merge(int t0, int t1) } #define HELPER_VECTOR_SPE_CMP(name) \ - uint32_t helper_ev##name(uint64_t op1, uint64_t op2) \ + uint32_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \ { \ - return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \ + return evcmp_merge(e##name(env, op1 >> 32, op2 >> 32), \ + e##name(env, op1, op2)); \ } /* evfststlt */ HELPER_VECTOR_SPE_CMP(fststlt); @@ -1451,7 +1459,7 @@ HELPER_VECTOR_SPE_CMP(fscmpgt); HELPER_VECTOR_SPE_CMP(fscmpeq); /* Double-precision floating-point conversion */ -uint64_t helper_efdcfsi(uint32_t val) +uint64_t helper_efdcfsi(CPUPPCState *env, uint32_t val) { CPU_DoubleU u; @@ -1460,7 +1468,7 @@ uint64_t helper_efdcfsi(uint32_t val) return u.ll; } -uint64_t helper_efdcfsid(uint64_t val) +uint64_t helper_efdcfsid(CPUPPCState *env, uint64_t val) { CPU_DoubleU u; @@ -1469,7 +1477,7 @@ uint64_t helper_efdcfsid(uint64_t val) return u.ll; } -uint64_t helper_efdcfui(uint32_t val) +uint64_t helper_efdcfui(CPUPPCState *env, uint32_t val) { CPU_DoubleU u; @@ -1478,7 +1486,7 @@ uint64_t helper_efdcfui(uint32_t val) return u.ll; } -uint64_t helper_efdcfuid(uint64_t val) +uint64_t helper_efdcfuid(CPUPPCState *env, uint64_t val) { CPU_DoubleU u; @@ -1487,7 +1495,7 @@ uint64_t helper_efdcfuid(uint64_t val) return u.ll; } -uint32_t helper_efdctsi(uint64_t val) +uint32_t helper_efdctsi(CPUPPCState *env, uint64_t val) { CPU_DoubleU u; @@ -1500,7 +1508,7 @@ uint32_t helper_efdctsi(uint64_t val) return float64_to_int32(u.d, &env->vec_status); } -uint32_t helper_efdctui(uint64_t val) +uint32_t helper_efdctui(CPUPPCState *env, uint64_t val) { CPU_DoubleU u; @@ -1513,7 +1521,7 @@ uint32_t helper_efdctui(uint64_t val) return float64_to_uint32(u.d, &env->vec_status); } -uint32_t helper_efdctsiz(uint64_t val) +uint32_t helper_efdctsiz(CPUPPCState *env, uint64_t val) { CPU_DoubleU u; @@ -1526,7 +1534,7 @@ uint32_t helper_efdctsiz(uint64_t val) return float64_to_int32_round_to_zero(u.d, &env->vec_status); } -uint64_t helper_efdctsidz(uint64_t val) +uint64_t helper_efdctsidz(CPUPPCState *env, uint64_t val) { CPU_DoubleU u; @@ -1539,7 +1547,7 @@ uint64_t helper_efdctsidz(uint64_t val) return float64_to_int64_round_to_zero(u.d, &env->vec_status); } -uint32_t helper_efdctuiz(uint64_t val) +uint32_t helper_efdctuiz(CPUPPCState *env, uint64_t val) { CPU_DoubleU u; @@ -1552,7 +1560,7 @@ uint32_t helper_efdctuiz(uint64_t val) return float64_to_uint32_round_to_zero(u.d, &env->vec_status); } -uint64_t helper_efdctuidz(uint64_t val) +uint64_t helper_efdctuidz(CPUPPCState *env, uint64_t val) { CPU_DoubleU u; @@ -1565,7 +1573,7 @@ uint64_t helper_efdctuidz(uint64_t val) return float64_to_uint64_round_to_zero(u.d, &env->vec_status); } -uint64_t helper_efdcfsf(uint32_t val) +uint64_t helper_efdcfsf(CPUPPCState *env, uint32_t val) { CPU_DoubleU u; float64 tmp; @@ -1577,7 +1585,7 @@ uint64_t helper_efdcfsf(uint32_t val) return u.ll; } -uint64_t helper_efdcfuf(uint32_t val) +uint64_t helper_efdcfuf(CPUPPCState *env, uint32_t val) { CPU_DoubleU u; float64 tmp; @@ -1589,7 +1597,7 @@ uint64_t helper_efdcfuf(uint32_t val) return u.ll; } -uint32_t helper_efdctsf(uint64_t val) +uint32_t helper_efdctsf(CPUPPCState *env, uint64_t val) { CPU_DoubleU u; float64 tmp; @@ -1605,7 +1613,7 @@ uint32_t helper_efdctsf(uint64_t val) return float64_to_int32(u.d, &env->vec_status); } -uint32_t helper_efdctuf(uint64_t val) +uint32_t helper_efdctuf(CPUPPCState *env, uint64_t val) { CPU_DoubleU u; float64 tmp; @@ -1621,7 +1629,7 @@ uint32_t helper_efdctuf(uint64_t val) return float64_to_uint32(u.d, &env->vec_status); } -uint32_t helper_efscfd(uint64_t val) +uint32_t helper_efscfd(CPUPPCState *env, uint64_t val) { CPU_DoubleU u1; CPU_FloatU u2; @@ -1632,7 +1640,7 @@ uint32_t helper_efscfd(uint64_t val) return u2.l; } -uint64_t helper_efdcfs(uint32_t val) +uint64_t helper_efdcfs(CPUPPCState *env, uint32_t val) { CPU_DoubleU u2; CPU_FloatU u1; @@ -1644,7 +1652,7 @@ uint64_t helper_efdcfs(uint32_t val) } /* Double precision fixed-point arithmetic */ -uint64_t helper_efdadd(uint64_t op1, uint64_t op2) +uint64_t helper_efdadd(CPUPPCState *env, uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; @@ -1654,7 +1662,7 @@ uint64_t helper_efdadd(uint64_t op1, uint64_t op2) return u1.ll; } -uint64_t helper_efdsub(uint64_t op1, uint64_t op2) +uint64_t helper_efdsub(CPUPPCState *env, uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; @@ -1664,7 +1672,7 @@ uint64_t helper_efdsub(uint64_t op1, uint64_t op2) return u1.ll; } -uint64_t helper_efdmul(uint64_t op1, uint64_t op2) +uint64_t helper_efdmul(CPUPPCState *env, uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; @@ -1674,7 +1682,7 @@ uint64_t helper_efdmul(uint64_t op1, uint64_t op2) return u1.ll; } -uint64_t helper_efddiv(uint64_t op1, uint64_t op2) +uint64_t helper_efddiv(CPUPPCState *env, uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; @@ -1685,7 +1693,7 @@ uint64_t helper_efddiv(uint64_t op1, uint64_t op2) } /* Double precision floating point helpers */ -uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2) +uint32_t helper_efdtstlt(CPUPPCState *env, uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; @@ -1694,7 +1702,7 @@ uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2) return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0; } -uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2) +uint32_t helper_efdtstgt(CPUPPCState *env, uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; @@ -1703,7 +1711,7 @@ uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2) return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4; } -uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2) +uint32_t helper_efdtsteq(CPUPPCState *env, uint64_t op1, uint64_t op2) { CPU_DoubleU u1, u2; @@ -1712,20 +1720,20 @@ uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2) return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0; } -uint32_t helper_efdcmplt(uint64_t op1, uint64_t op2) +uint32_t helper_efdcmplt(CPUPPCState *env, uint64_t op1, uint64_t op2) { /* XXX: TODO: test special values (NaN, infinites, ...) */ - return helper_efdtstlt(op1, op2); + return helper_efdtstlt(env, op1, op2); } -uint32_t helper_efdcmpgt(uint64_t op1, uint64_t op2) +uint32_t helper_efdcmpgt(CPUPPCState *env, uint64_t op1, uint64_t op2) { /* XXX: TODO: test special values (NaN, infinites, ...) */ - return helper_efdtstgt(op1, op2); + return helper_efdtstgt(env, op1, op2); } -uint32_t helper_efdcmpeq(uint64_t op1, uint64_t op2) +uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2) { /* XXX: TODO: test special values (NaN, infinites, ...) */ - return helper_efdtsteq(op1, op2); + return helper_efdtsteq(env, op1, op2); } diff --git a/target-ppc/helper.h b/target-ppc/helper.h index a4562ae47c..0aba7f8e1a 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -50,47 +50,47 @@ DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) DEF_HELPER_FLAGS_1(cntlzw32, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) DEF_HELPER_FLAGS_2(brinc, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl) -DEF_HELPER_0(float_check_status, void) -DEF_HELPER_0(reset_fpstatus, void) -DEF_HELPER_2(compute_fprf, i32, i64, i32) -DEF_HELPER_2(store_fpscr, void, i64, i32) -DEF_HELPER_1(fpscr_clrbit, void, i32) -DEF_HELPER_1(fpscr_setbit, void, i32) -DEF_HELPER_1(float64_to_float32, i32, i64) -DEF_HELPER_1(float32_to_float64, i64, i32) +DEF_HELPER_1(float_check_status, void, env) +DEF_HELPER_1(reset_fpstatus, void, env) +DEF_HELPER_3(compute_fprf, i32, env, i64, i32) +DEF_HELPER_3(store_fpscr, void, env, i64, i32) +DEF_HELPER_2(fpscr_clrbit, void, env, i32) +DEF_HELPER_2(fpscr_setbit, void, env, i32) +DEF_HELPER_2(float64_to_float32, i32, env, i64) +DEF_HELPER_2(float32_to_float64, i64, env, i32) -DEF_HELPER_3(fcmpo, void, i64, i64, i32) -DEF_HELPER_3(fcmpu, void, i64, i64, i32) +DEF_HELPER_4(fcmpo, void, env, i64, i64, i32) +DEF_HELPER_4(fcmpu, void, env, i64, i64, i32) -DEF_HELPER_1(fctiw, i64, i64) -DEF_HELPER_1(fctiwz, i64, i64) +DEF_HELPER_2(fctiw, i64, env, i64) +DEF_HELPER_2(fctiwz, i64, env, i64) #if defined(TARGET_PPC64) -DEF_HELPER_1(fcfid, i64, i64) -DEF_HELPER_1(fctid, i64, i64) -DEF_HELPER_1(fctidz, i64, i64) +DEF_HELPER_2(fcfid, i64, env, i64) +DEF_HELPER_2(fctid, i64, env, i64) +DEF_HELPER_2(fctidz, i64, env, i64) #endif -DEF_HELPER_1(frsp, i64, i64) -DEF_HELPER_1(frin, i64, i64) -DEF_HELPER_1(friz, i64, i64) -DEF_HELPER_1(frip, i64, i64) -DEF_HELPER_1(frim, i64, i64) +DEF_HELPER_2(frsp, i64, env, i64) +DEF_HELPER_2(frin, i64, env, i64) +DEF_HELPER_2(friz, i64, env, i64) +DEF_HELPER_2(frip, i64, env, i64) +DEF_HELPER_2(frim, i64, env, i64) -DEF_HELPER_2(fadd, i64, i64, i64) -DEF_HELPER_2(fsub, i64, i64, i64) -DEF_HELPER_2(fmul, i64, i64, i64) -DEF_HELPER_2(fdiv, i64, i64, i64) -DEF_HELPER_3(fmadd, i64, i64, i64, i64) -DEF_HELPER_3(fmsub, i64, i64, i64, i64) -DEF_HELPER_3(fnmadd, i64, i64, i64, i64) -DEF_HELPER_3(fnmsub, i64, i64, i64, i64) -DEF_HELPER_1(fabs, i64, i64) -DEF_HELPER_1(fnabs, i64, i64) -DEF_HELPER_1(fneg, i64, i64) -DEF_HELPER_1(fsqrt, i64, i64) -DEF_HELPER_1(fre, i64, i64) -DEF_HELPER_1(fres, i64, i64) -DEF_HELPER_1(frsqrte, i64, i64) -DEF_HELPER_3(fsel, i64, i64, i64, i64) +DEF_HELPER_3(fadd, i64, env, i64, i64) +DEF_HELPER_3(fsub, i64, env, i64, i64) +DEF_HELPER_3(fmul, i64, env, i64, i64) +DEF_HELPER_3(fdiv, i64, env, i64, i64) +DEF_HELPER_4(fmadd, i64, env, i64, i64, i64) +DEF_HELPER_4(fmsub, i64, env, i64, i64, i64) +DEF_HELPER_4(fnmadd, i64, env, i64, i64, i64) +DEF_HELPER_4(fnmsub, i64, env, i64, i64, i64) +DEF_HELPER_2(fabs, i64, env, i64) +DEF_HELPER_2(fnabs, i64, env, i64) +DEF_HELPER_2(fneg, i64, env, i64) +DEF_HELPER_2(fsqrt, i64, env, i64) +DEF_HELPER_2(fre, i64, env, i64) +DEF_HELPER_2(fres, i64, env, i64) +DEF_HELPER_2(frsqrte, i64, env, i64) +DEF_HELPER_4(fsel, i64, env, i64, i64, i64) #define dh_alias_avr ptr #define dh_ctype_avr ppc_avr_t * @@ -256,72 +256,72 @@ DEF_HELPER_3(vcfsx, void, avr, avr, i32) DEF_HELPER_3(vctuxs, void, avr, avr, i32) DEF_HELPER_3(vctsxs, void, avr, avr, i32) -DEF_HELPER_1(efscfsi, i32, i32) -DEF_HELPER_1(efscfui, i32, i32) -DEF_HELPER_1(efscfuf, i32, i32) -DEF_HELPER_1(efscfsf, i32, i32) -DEF_HELPER_1(efsctsi, i32, i32) -DEF_HELPER_1(efsctui, i32, i32) -DEF_HELPER_1(efsctsiz, i32, i32) -DEF_HELPER_1(efsctuiz, i32, i32) -DEF_HELPER_1(efsctsf, i32, i32) -DEF_HELPER_1(efsctuf, i32, i32) -DEF_HELPER_1(evfscfsi, i64, i64) -DEF_HELPER_1(evfscfui, i64, i64) -DEF_HELPER_1(evfscfuf, i64, i64) -DEF_HELPER_1(evfscfsf, i64, i64) -DEF_HELPER_1(evfsctsi, i64, i64) -DEF_HELPER_1(evfsctui, i64, i64) -DEF_HELPER_1(evfsctsiz, i64, i64) -DEF_HELPER_1(evfsctuiz, i64, i64) -DEF_HELPER_1(evfsctsf, i64, i64) -DEF_HELPER_1(evfsctuf, i64, i64) -DEF_HELPER_2(efsadd, i32, i32, i32) -DEF_HELPER_2(efssub, i32, i32, i32) -DEF_HELPER_2(efsmul, i32, i32, i32) -DEF_HELPER_2(efsdiv, i32, i32, i32) -DEF_HELPER_2(evfsadd, i64, i64, i64) -DEF_HELPER_2(evfssub, i64, i64, i64) -DEF_HELPER_2(evfsmul, i64, i64, i64) -DEF_HELPER_2(evfsdiv, i64, i64, i64) -DEF_HELPER_2(efststlt, i32, i32, i32) -DEF_HELPER_2(efststgt, i32, i32, i32) -DEF_HELPER_2(efststeq, i32, i32, i32) -DEF_HELPER_2(efscmplt, i32, i32, i32) -DEF_HELPER_2(efscmpgt, i32, i32, i32) -DEF_HELPER_2(efscmpeq, i32, i32, i32) -DEF_HELPER_2(evfststlt, i32, i64, i64) -DEF_HELPER_2(evfststgt, i32, i64, i64) -DEF_HELPER_2(evfststeq, i32, i64, i64) -DEF_HELPER_2(evfscmplt, i32, i64, i64) -DEF_HELPER_2(evfscmpgt, i32, i64, i64) -DEF_HELPER_2(evfscmpeq, i32, i64, i64) -DEF_HELPER_1(efdcfsi, i64, i32) -DEF_HELPER_1(efdcfsid, i64, i64) -DEF_HELPER_1(efdcfui, i64, i32) -DEF_HELPER_1(efdcfuid, i64, i64) -DEF_HELPER_1(efdctsi, i32, i64) -DEF_HELPER_1(efdctui, i32, i64) -DEF_HELPER_1(efdctsiz, i32, i64) -DEF_HELPER_1(efdctsidz, i64, i64) -DEF_HELPER_1(efdctuiz, i32, i64) -DEF_HELPER_1(efdctuidz, i64, i64) -DEF_HELPER_1(efdcfsf, i64, i32) -DEF_HELPER_1(efdcfuf, i64, i32) -DEF_HELPER_1(efdctsf, i32, i64) -DEF_HELPER_1(efdctuf, i32, i64) -DEF_HELPER_1(efscfd, i32, i64) -DEF_HELPER_1(efdcfs, i64, i32) -DEF_HELPER_2(efdadd, i64, i64, i64) -DEF_HELPER_2(efdsub, i64, i64, i64) -DEF_HELPER_2(efdmul, i64, i64, i64) -DEF_HELPER_2(efddiv, i64, i64, i64) -DEF_HELPER_2(efdtstlt, i32, i64, i64) -DEF_HELPER_2(efdtstgt, i32, i64, i64) -DEF_HELPER_2(efdtsteq, i32, i64, i64) -DEF_HELPER_2(efdcmplt, i32, i64, i64) -DEF_HELPER_2(efdcmpgt, i32, i64, i64) -DEF_HELPER_2(efdcmpeq, i32, i64, i64) +DEF_HELPER_2(efscfsi, i32, env, i32) +DEF_HELPER_2(efscfui, i32, env, i32) +DEF_HELPER_2(efscfuf, i32, env, i32) +DEF_HELPER_2(efscfsf, i32, env, i32) +DEF_HELPER_2(efsctsi, i32, env, i32) +DEF_HELPER_2(efsctui, i32, env, i32) +DEF_HELPER_2(efsctsiz, i32, env, i32) +DEF_HELPER_2(efsctuiz, i32, env, i32) +DEF_HELPER_2(efsctsf, i32, env, i32) +DEF_HELPER_2(efsctuf, i32, env, i32) +DEF_HELPER_2(evfscfsi, i64, env, i64) +DEF_HELPER_2(evfscfui, i64, env, i64) +DEF_HELPER_2(evfscfuf, i64, env, i64) +DEF_HELPER_2(evfscfsf, i64, env, i64) +DEF_HELPER_2(evfsctsi, i64, env, i64) +DEF_HELPER_2(evfsctui, i64, env, i64) +DEF_HELPER_2(evfsctsiz, i64, env, i64) +DEF_HELPER_2(evfsctuiz, i64, env, i64) +DEF_HELPER_2(evfsctsf, i64, env, i64) +DEF_HELPER_2(evfsctuf, i64, env, i64) +DEF_HELPER_3(efsadd, i32, env, i32, i32) +DEF_HELPER_3(efssub, i32, env, i32, i32) +DEF_HELPER_3(efsmul, i32, env, i32, i32) +DEF_HELPER_3(efsdiv, i32, env, i32, i32) +DEF_HELPER_3(evfsadd, i64, env, i64, i64) +DEF_HELPER_3(evfssub, i64, env, i64, i64) +DEF_HELPER_3(evfsmul, i64, env, i64, i64) +DEF_HELPER_3(evfsdiv, i64, env, i64, i64) +DEF_HELPER_3(efststlt, i32, env, i32, i32) +DEF_HELPER_3(efststgt, i32, env, i32, i32) +DEF_HELPER_3(efststeq, i32, env, i32, i32) +DEF_HELPER_3(efscmplt, i32, env, i32, i32) +DEF_HELPER_3(efscmpgt, i32, env, i32, i32) +DEF_HELPER_3(efscmpeq, i32, env, i32, i32) +DEF_HELPER_3(evfststlt, i32, env, i64, i64) +DEF_HELPER_3(evfststgt, i32, env, i64, i64) +DEF_HELPER_3(evfststeq, i32, env, i64, i64) +DEF_HELPER_3(evfscmplt, i32, env, i64, i64) +DEF_HELPER_3(evfscmpgt, i32, env, i64, i64) +DEF_HELPER_3(evfscmpeq, i32, env, i64, i64) +DEF_HELPER_2(efdcfsi, i64, env, i32) +DEF_HELPER_2(efdcfsid, i64, env, i64) +DEF_HELPER_2(efdcfui, i64, env, i32) +DEF_HELPER_2(efdcfuid, i64, env, i64) +DEF_HELPER_2(efdctsi, i32, env, i64) +DEF_HELPER_2(efdctui, i32, env, i64) +DEF_HELPER_2(efdctsiz, i32, env, i64) +DEF_HELPER_2(efdctsidz, i64, env, i64) +DEF_HELPER_2(efdctuiz, i32, env, i64) +DEF_HELPER_2(efdctuidz, i64, env, i64) +DEF_HELPER_2(efdcfsf, i64, env, i32) +DEF_HELPER_2(efdcfuf, i64, env, i32) +DEF_HELPER_2(efdctsf, i32, env, i64) +DEF_HELPER_2(efdctuf, i32, env, i64) +DEF_HELPER_2(efscfd, i32, env, i64) +DEF_HELPER_2(efdcfs, i64, env, i32) +DEF_HELPER_3(efdadd, i64, env, i64, i64) +DEF_HELPER_3(efdsub, i64, env, i64, i64) +DEF_HELPER_3(efdmul, i64, env, i64, i64) +DEF_HELPER_3(efddiv, i64, env, i64, i64) +DEF_HELPER_3(efdtstlt, i32, env, i64, i64) +DEF_HELPER_3(efdtstgt, i32, env, i64, i64) +DEF_HELPER_3(efdtsteq, i32, env, i64, i64) +DEF_HELPER_3(efdcmplt, i32, env, i64, i64) +DEF_HELPER_3(efdcmpgt, i32, env, i64, i64) +DEF_HELPER_3(efdcmpeq, i32, env, i64, i64) #if !defined(CONFIG_USER_ONLY) DEF_HELPER_1(4xx_tlbre_hi, tl, tl) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 02626ae349..c8b7982e0b 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -219,7 +219,7 @@ struct opc_handler_t { static inline void gen_reset_fpstatus(void) { - gen_helper_reset_fpstatus(); + gen_helper_reset_fpstatus(cpu_env); } static inline void gen_compute_fprf(TCGv_i64 arg, int set_fprf, int set_rc) @@ -229,15 +229,15 @@ static inline void gen_compute_fprf(TCGv_i64 arg, int set_fprf, int set_rc) if (set_fprf != 0) { /* This case might be optimized later */ tcg_gen_movi_i32(t0, 1); - gen_helper_compute_fprf(t0, arg, t0); + gen_helper_compute_fprf(t0, cpu_env, arg, t0); if (unlikely(set_rc)) { tcg_gen_mov_i32(cpu_crf[1], t0); } - gen_helper_float_check_status(); + gen_helper_float_check_status(cpu_env); } else if (unlikely(set_rc)) { /* We always need to compute fpcc */ tcg_gen_movi_i32(t0, 0); - gen_helper_compute_fprf(t0, arg, t0); + gen_helper_compute_fprf(t0, cpu_env, arg, t0); tcg_gen_mov_i32(cpu_crf[1], t0); } @@ -2027,10 +2027,12 @@ static void gen_f##name(DisasContext *ctx) \ /* NIP cannot be restored if the memory exception comes from an helper */ \ gen_update_nip(ctx, ctx->nip - 4); \ gen_reset_fpstatus(); \ - gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], \ + gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rA(ctx->opcode)], \ cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); \ if (isfloat) { \ - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]); \ + gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rD(ctx->opcode)]); \ } \ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], set_fprf, \ Rc(ctx->opcode) != 0); \ @@ -2050,10 +2052,12 @@ static void gen_f##name(DisasContext *ctx) \ /* NIP cannot be restored if the memory exception comes from an helper */ \ gen_update_nip(ctx, ctx->nip - 4); \ gen_reset_fpstatus(); \ - gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], \ + gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rA(ctx->opcode)], \ cpu_fpr[rB(ctx->opcode)]); \ if (isfloat) { \ - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]); \ + gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rD(ctx->opcode)]); \ } \ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \ set_fprf, Rc(ctx->opcode) != 0); \ @@ -2072,10 +2076,12 @@ static void gen_f##name(DisasContext *ctx) \ /* NIP cannot be restored if the memory exception comes from an helper */ \ gen_update_nip(ctx, ctx->nip - 4); \ gen_reset_fpstatus(); \ - gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], \ - cpu_fpr[rC(ctx->opcode)]); \ + gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rA(ctx->opcode)], \ + cpu_fpr[rC(ctx->opcode)]); \ if (isfloat) { \ - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]); \ + gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rD(ctx->opcode)]); \ } \ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \ set_fprf, Rc(ctx->opcode) != 0); \ @@ -2094,7 +2100,8 @@ static void gen_f##name(DisasContext *ctx) \ /* NIP cannot be restored if the memory exception comes from an helper */ \ gen_update_nip(ctx, ctx->nip - 4); \ gen_reset_fpstatus(); \ - gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); \ + gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rB(ctx->opcode)]); \ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \ set_fprf, Rc(ctx->opcode) != 0); \ } @@ -2109,7 +2116,8 @@ static void gen_f##name(DisasContext *ctx) \ /* NIP cannot be restored if the memory exception comes from an helper */ \ gen_update_nip(ctx, ctx->nip - 4); \ gen_reset_fpstatus(); \ - gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); \ + gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ + cpu_fpr[rB(ctx->opcode)]); \ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \ set_fprf, Rc(ctx->opcode) != 0); \ } @@ -2140,8 +2148,10 @@ static void gen_frsqrtes(DisasContext *ctx) /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); gen_reset_fpstatus(); - gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]); + gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env, + cpu_fpr[rB(ctx->opcode)]); + gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, + cpu_fpr[rD(ctx->opcode)]); gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0); } @@ -2161,7 +2171,8 @@ static void gen_fsqrt(DisasContext *ctx) /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); gen_reset_fpstatus(); - gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); + gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env, + cpu_fpr[rB(ctx->opcode)]); gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0); } @@ -2174,8 +2185,10 @@ static void gen_fsqrts(DisasContext *ctx) /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); gen_reset_fpstatus(); - gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); - gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]); + gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env, + cpu_fpr[rB(ctx->opcode)]); + gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, + cpu_fpr[rD(ctx->opcode)]); gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0); } @@ -2228,9 +2241,10 @@ static void gen_fcmpo(DisasContext *ctx) gen_update_nip(ctx, ctx->nip - 4); gen_reset_fpstatus(); crf = tcg_const_i32(crfD(ctx->opcode)); - gen_helper_fcmpo(cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], crf); + gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)], + cpu_fpr[rB(ctx->opcode)], crf); tcg_temp_free_i32(crf); - gen_helper_float_check_status(); + gen_helper_float_check_status(cpu_env); } /* fcmpu */ @@ -2245,9 +2259,10 @@ static void gen_fcmpu(DisasContext *ctx) gen_update_nip(ctx, ctx->nip - 4); gen_reset_fpstatus(); crf = tcg_const_i32(crfD(ctx->opcode)); - gen_helper_fcmpu(cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], crf); + gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)], + cpu_fpr[rB(ctx->opcode)], crf); tcg_temp_free_i32(crf); - gen_helper_float_check_status(); + gen_helper_float_check_status(cpu_env); } /*** Floating-point move ***/ @@ -2319,7 +2334,7 @@ static void gen_mtfsb0(DisasContext *ctx) /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_const_i32(crb); - gen_helper_fpscr_clrbit(t0); + gen_helper_fpscr_clrbit(cpu_env, t0); tcg_temp_free_i32(t0); } if (unlikely(Rc(ctx->opcode) != 0)) { @@ -2344,14 +2359,14 @@ static void gen_mtfsb1(DisasContext *ctx) /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_const_i32(crb); - gen_helper_fpscr_setbit(t0); + gen_helper_fpscr_setbit(cpu_env, t0); tcg_temp_free_i32(t0); } if (unlikely(Rc(ctx->opcode) != 0)) { tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX); } /* We can raise a differed exception */ - gen_helper_float_check_status(); + gen_helper_float_check_status(cpu_env); } /* mtfsf */ @@ -2371,13 +2386,13 @@ static void gen_mtfsf(DisasContext *ctx) t0 = tcg_const_i32(0xff); else t0 = tcg_const_i32(FM(ctx->opcode)); - gen_helper_store_fpscr(cpu_fpr[rB(ctx->opcode)], t0); + gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0); tcg_temp_free_i32(t0); if (unlikely(Rc(ctx->opcode) != 0)) { tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX); } /* We can raise a differed exception */ - gen_helper_float_check_status(); + gen_helper_float_check_status(cpu_env); } /* mtfsfi */ @@ -2398,14 +2413,14 @@ static void gen_mtfsfi(DisasContext *ctx) gen_reset_fpstatus(); t0 = tcg_const_i64(FPIMM(ctx->opcode) << (4 * sh)); t1 = tcg_const_i32(1 << sh); - gen_helper_store_fpscr(t0, t1); + gen_helper_store_fpscr(cpu_env, t0, t1); tcg_temp_free_i64(t0); tcg_temp_free_i32(t1); if (unlikely(Rc(ctx->opcode) != 0)) { tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX); } /* We can raise a differed exception */ - gen_helper_float_check_status(); + gen_helper_float_check_status(cpu_env); } /*** Addressing modes ***/ @@ -3303,7 +3318,7 @@ static inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) gen_qemu_ld32u(ctx, t0, arg2); tcg_gen_trunc_tl_i32(t1, t0); tcg_temp_free(t0); - gen_helper_float32_to_float64(arg1, t1); + gen_helper_float32_to_float64(arg1, cpu_env, t1); tcg_temp_free_i32(t1); } @@ -3393,7 +3408,7 @@ static inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) { TCGv_i32 t0 = tcg_temp_new_i32(); TCGv t1 = tcg_temp_new(); - gen_helper_float64_to_float32(t0, arg1); + gen_helper_float64_to_float32(t0, cpu_env, arg1); tcg_gen_extu_i32_tl(t1, t0); tcg_temp_free_i32(t0); gen_qemu_st32(ctx, t1, arg2); @@ -8010,7 +8025,7 @@ static inline void gen_##name(DisasContext *ctx) \ TCGv t1; \ t0 = tcg_temp_new_i32(); \ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(t0, t0); \ + gen_helper_##name(t0, cpu_env, t0); \ t1 = tcg_temp_new(); \ tcg_gen_extu_i32_tl(t1, t0); \ tcg_temp_free_i32(t0); \ @@ -8025,7 +8040,7 @@ static inline void gen_##name(DisasContext *ctx) \ TCGv_i32 t0; \ TCGv t1; \ t0 = tcg_temp_new_i32(); \ - gen_helper_##name(t0, cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(t0, cpu_env, cpu_gpr[rB(ctx->opcode)]); \ t1 = tcg_temp_new(); \ tcg_gen_extu_i32_tl(t1, t0); \ tcg_temp_free_i32(t0); \ @@ -8039,13 +8054,14 @@ static inline void gen_##name(DisasContext *ctx) \ { \ TCGv_i32 t0 = tcg_temp_new_i32(); \ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(cpu_gpr[rD(ctx->opcode)], t0); \ + gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); \ tcg_temp_free_i32(t0); \ } #define GEN_SPEFPUOP_CONV_64_64(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ - gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, \ + cpu_gpr[rB(ctx->opcode)]); \ } #define GEN_SPEFPUOP_ARITH2_32_32(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -8060,7 +8076,7 @@ static inline void gen_##name(DisasContext *ctx) \ t1 = tcg_temp_new_i32(); \ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(t0, t0, t1); \ + gen_helper_##name(t0, cpu_env, t0, t1); \ tcg_temp_free_i32(t1); \ t2 = tcg_temp_new(); \ tcg_gen_extu_i32_tl(t2, t0); \ @@ -8077,8 +8093,8 @@ static inline void gen_##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_SPEU); \ return; \ } \ - gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], \ - cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, \ + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ } #define GEN_SPEFPUOP_COMP_32(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -8092,7 +8108,7 @@ static inline void gen_##name(DisasContext *ctx) \ t1 = tcg_temp_new_i32(); \ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], t0, t1); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \ tcg_temp_free_i32(t0); \ tcg_temp_free_i32(t1); \ } @@ -8103,28 +8119,29 @@ static inline void gen_##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_SPEU); \ return; \ } \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, \ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ } #else #define GEN_SPEFPUOP_CONV_32_32(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ - gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, \ + cpu_gpr[rB(ctx->opcode)]); \ } #define GEN_SPEFPUOP_CONV_32_64(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ TCGv_i64 t0 = tcg_temp_new_i64(); \ gen_load_gpr64(t0, rB(ctx->opcode)); \ - gen_helper_##name(cpu_gpr[rD(ctx->opcode)], t0); \ + gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); \ tcg_temp_free_i64(t0); \ } #define GEN_SPEFPUOP_CONV_64_32(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ TCGv_i64 t0 = tcg_temp_new_i64(); \ - gen_helper_##name(t0, cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(t0, cpu_env, cpu_gpr[rB(ctx->opcode)]); \ gen_store_gpr64(rD(ctx->opcode), t0); \ tcg_temp_free_i64(t0); \ } @@ -8133,7 +8150,7 @@ static inline void gen_##name(DisasContext *ctx) \ { \ TCGv_i64 t0 = tcg_temp_new_i64(); \ gen_load_gpr64(t0, rB(ctx->opcode)); \ - gen_helper_##name(t0, t0); \ + gen_helper_##name(t0, cpu_env, t0); \ gen_store_gpr64(rD(ctx->opcode), t0); \ tcg_temp_free_i64(t0); \ } @@ -8144,7 +8161,7 @@ static inline void gen_##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_SPEU); \ return; \ } \ - gen_helper_##name(cpu_gpr[rD(ctx->opcode)], \ + gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, \ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ } #define GEN_SPEFPUOP_ARITH2_64_64(name) \ @@ -8159,7 +8176,7 @@ static inline void gen_##name(DisasContext *ctx) \ t1 = tcg_temp_new_i64(); \ gen_load_gpr64(t0, rA(ctx->opcode)); \ gen_load_gpr64(t1, rB(ctx->opcode)); \ - gen_helper_##name(t0, t0, t1); \ + gen_helper_##name(t0, cpu_env, t0, t1); \ gen_store_gpr64(rD(ctx->opcode), t0); \ tcg_temp_free_i64(t0); \ tcg_temp_free_i64(t1); \ @@ -8171,7 +8188,7 @@ static inline void gen_##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_SPEU); \ return; \ } \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, \ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ } #define GEN_SPEFPUOP_COMP_64(name) \ @@ -8186,7 +8203,7 @@ static inline void gen_##name(DisasContext *ctx) \ t1 = tcg_temp_new_i64(); \ gen_load_gpr64(t0, rA(ctx->opcode)); \ gen_load_gpr64(t1, rB(ctx->opcode)); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], t0, t1); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \ tcg_temp_free_i64(t0); \ tcg_temp_free_i64(t1); \ } From 64654ded79762878a6207ccb9b299c69e9a90acf Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:28 +0000 Subject: [PATCH 08/72] ppc: Split integer and vector ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move integer and vector ops to int_helper.c. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 2 + target-ppc/int_helper.c | 1538 ++++++++++++++++++++++++++++++++++++++ target-ppc/op_helper.c | 1500 ------------------------------------- 3 files changed, 1540 insertions(+), 1500 deletions(-) create mode 100644 target-ppc/int_helper.c diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 5bea9c3377..97e440be85 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -4,5 +4,7 @@ obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o obj-y += op_helper.o helper.o obj-y += excp_helper.o obj-y += fpu_helper.o +obj-y += int_helper.o +$(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c new file mode 100644 index 0000000000..71c7304b57 --- /dev/null +++ b/target-ppc/int_helper.c @@ -0,0 +1,1538 @@ +/* + * PowerPC integer and vector emulation 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, see . + */ +#include "cpu.h" +#include "dyngen-exec.h" +#include "host-utils.h" +#include "helper.h" + +#include "helper_regs.h" +/*****************************************************************************/ +/* Fixed point operations helpers */ +#if defined(TARGET_PPC64) + +/* multiply high word */ +uint64_t helper_mulhd(uint64_t arg1, uint64_t arg2) +{ + uint64_t tl, th; + + muls64(&tl, &th, arg1, arg2); + return th; +} + +/* multiply high word unsigned */ +uint64_t helper_mulhdu(uint64_t arg1, uint64_t arg2) +{ + uint64_t tl, th; + + mulu64(&tl, &th, arg1, arg2); + return th; +} + +uint64_t helper_mulldo(uint64_t arg1, uint64_t arg2) +{ + int64_t th; + uint64_t tl; + + muls64(&tl, (uint64_t *)&th, arg1, arg2); + /* If th != 0 && th != -1, then we had an overflow */ + if (likely((uint64_t)(th + 1) <= 1)) { + env->xer &= ~(1 << XER_OV); + } else { + env->xer |= (1 << XER_OV) | (1 << XER_SO); + } + return (int64_t)tl; +} +#endif + +target_ulong helper_cntlzw(target_ulong t) +{ + return clz32(t); +} + +#if defined(TARGET_PPC64) +target_ulong helper_cntlzd(target_ulong t) +{ + return clz64(t); +} +#endif + +/* shift right arithmetic helper */ +target_ulong helper_sraw(target_ulong value, target_ulong shift) +{ + int32_t ret; + + if (likely(!(shift & 0x20))) { + if (likely((uint32_t)shift != 0)) { + shift &= 0x1f; + ret = (int32_t)value >> shift; + if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) { + env->xer &= ~(1 << XER_CA); + } else { + env->xer |= (1 << XER_CA); + } + } else { + ret = (int32_t)value; + env->xer &= ~(1 << XER_CA); + } + } else { + ret = (int32_t)value >> 31; + if (ret) { + env->xer |= (1 << XER_CA); + } else { + env->xer &= ~(1 << XER_CA); + } + } + return (target_long)ret; +} + +#if defined(TARGET_PPC64) +target_ulong helper_srad(target_ulong value, target_ulong shift) +{ + int64_t ret; + + if (likely(!(shift & 0x40))) { + if (likely((uint64_t)shift != 0)) { + shift &= 0x3f; + ret = (int64_t)value >> shift; + if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) { + env->xer &= ~(1 << XER_CA); + } else { + env->xer |= (1 << XER_CA); + } + } else { + ret = (int64_t)value; + env->xer &= ~(1 << XER_CA); + } + } else { + ret = (int64_t)value >> 63; + if (ret) { + env->xer |= (1 << XER_CA); + } else { + env->xer &= ~(1 << XER_CA); + } + } + return ret; +} +#endif + +#if defined(TARGET_PPC64) +target_ulong helper_popcntb(target_ulong val) +{ + val = (val & 0x5555555555555555ULL) + ((val >> 1) & + 0x5555555555555555ULL); + val = (val & 0x3333333333333333ULL) + ((val >> 2) & + 0x3333333333333333ULL); + val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & + 0x0f0f0f0f0f0f0f0fULL); + return val; +} + +target_ulong helper_popcntw(target_ulong val) +{ + val = (val & 0x5555555555555555ULL) + ((val >> 1) & + 0x5555555555555555ULL); + val = (val & 0x3333333333333333ULL) + ((val >> 2) & + 0x3333333333333333ULL); + val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & + 0x0f0f0f0f0f0f0f0fULL); + val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) & + 0x00ff00ff00ff00ffULL); + val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) & + 0x0000ffff0000ffffULL); + return val; +} + +target_ulong helper_popcntd(target_ulong val) +{ + return ctpop64(val); +} +#else +target_ulong helper_popcntb(target_ulong val) +{ + val = (val & 0x55555555) + ((val >> 1) & 0x55555555); + val = (val & 0x33333333) + ((val >> 2) & 0x33333333); + val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f); + return val; +} + +target_ulong helper_popcntw(target_ulong val) +{ + val = (val & 0x55555555) + ((val >> 1) & 0x55555555); + val = (val & 0x33333333) + ((val >> 2) & 0x33333333); + val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f); + val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff); + val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff); + return val; +} +#endif + +/*****************************************************************************/ +/* PowerPC 601 specific instructions (POWER bridge) */ +target_ulong helper_div(target_ulong arg1, target_ulong arg2) +{ + uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ]; + + if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || + (int32_t)arg2 == 0) { + env->spr[SPR_MQ] = 0; + return INT32_MIN; + } else { + env->spr[SPR_MQ] = tmp % arg2; + return tmp / (int32_t)arg2; + } +} + +target_ulong helper_divo(target_ulong arg1, target_ulong arg2) +{ + uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ]; + + if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || + (int32_t)arg2 == 0) { + env->xer |= (1 << XER_OV) | (1 << XER_SO); + env->spr[SPR_MQ] = 0; + return INT32_MIN; + } else { + env->spr[SPR_MQ] = tmp % arg2; + tmp /= (int32_t)arg2; + if ((int32_t)tmp != tmp) { + env->xer |= (1 << XER_OV) | (1 << XER_SO); + } else { + env->xer &= ~(1 << XER_OV); + } + return tmp; + } +} + +target_ulong helper_divs(target_ulong arg1, target_ulong arg2) +{ + if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || + (int32_t)arg2 == 0) { + env->spr[SPR_MQ] = 0; + return INT32_MIN; + } else { + env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2; + return (int32_t)arg1 / (int32_t)arg2; + } +} + +target_ulong helper_divso(target_ulong arg1, target_ulong arg2) +{ + if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || + (int32_t)arg2 == 0) { + env->xer |= (1 << XER_OV) | (1 << XER_SO); + env->spr[SPR_MQ] = 0; + return INT32_MIN; + } else { + env->xer &= ~(1 << XER_OV); + env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2; + return (int32_t)arg1 / (int32_t)arg2; + } +} + +/*****************************************************************************/ +/* 602 specific instructions */ +/* mfrom is the most crazy instruction ever seen, imho ! */ +/* Real implementation uses a ROM table. Do the same */ +/* Extremely decomposed: + * -arg / 256 + * return 256 * log10(10 + 1.0) + 0.5 + */ +#if !defined(CONFIG_USER_ONLY) +target_ulong helper_602_mfrom(target_ulong arg) +{ + if (likely(arg < 602)) { +#include "mfrom_table.c" + return mfrom_ROM_table[arg]; + } else { + return 0; + } +} +#endif + +/*****************************************************************************/ +/* Altivec extension helpers */ +#if defined(HOST_WORDS_BIGENDIAN) +#define HI_IDX 0 +#define LO_IDX 1 +#else +#define HI_IDX 1 +#define LO_IDX 0 +#endif + +#if defined(HOST_WORDS_BIGENDIAN) +#define VECTOR_FOR_INORDER_I(index, element) \ + for (index = 0; index < ARRAY_SIZE(r->element); index++) +#else +#define VECTOR_FOR_INORDER_I(index, element) \ + for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--) +#endif + +/* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise, + * execute the following block. */ +#define DO_HANDLE_NAN(result, x) \ + if (float32_is_any_nan(x)) { \ + CPU_FloatU __f; \ + __f.f = x; \ + __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \ + result = __f.f; \ + } else + +#define HANDLE_NAN1(result, x) \ + DO_HANDLE_NAN(result, x) +#define HANDLE_NAN2(result, x, y) \ + DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) +#define HANDLE_NAN3(result, x, y, z) \ + DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z) + +/* Saturating arithmetic helpers. */ +#define SATCVT(from, to, from_type, to_type, min, max) \ + static inline to_type cvt##from##to(from_type x, int *sat) \ + { \ + to_type r; \ + \ + if (x < (from_type)min) { \ + r = min; \ + *sat = 1; \ + } else if (x > (from_type)max) { \ + r = max; \ + *sat = 1; \ + } else { \ + r = x; \ + } \ + return r; \ + } +#define SATCVTU(from, to, from_type, to_type, min, max) \ + static inline to_type cvt##from##to(from_type x, int *sat) \ + { \ + to_type r; \ + \ + if (x > (from_type)max) { \ + r = max; \ + *sat = 1; \ + } else { \ + r = x; \ + } \ + return r; \ + } +SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX) +SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX) +SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX) + +SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX) +SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX) +SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX) +SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX) +SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX) +SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX) +#undef SATCVT +#undef SATCVTU + +void helper_lvsl(ppc_avr_t *r, target_ulong sh) +{ + int i, j = (sh & 0xf); + + VECTOR_FOR_INORDER_I(i, u8) { + r->u8[i] = j++; + } +} + +void helper_lvsr(ppc_avr_t *r, target_ulong sh) +{ + int i, j = 0x10 - (sh & 0xf); + + VECTOR_FOR_INORDER_I(i, u8) { + r->u8[i] = j++; + } +} + +void helper_mtvscr(ppc_avr_t *r) +{ +#if defined(HOST_WORDS_BIGENDIAN) + env->vscr = r->u32[3]; +#else + env->vscr = r->u32[0]; +#endif + set_flush_to_zero(vscr_nj, &env->vec_status); +} + +void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(r->u32); i++) { + r->u32[i] = ~a->u32[i] < b->u32[i]; + } +} + +#define VARITH_DO(name, op, element) \ + void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + r->element[i] = a->element[i] op b->element[i]; \ + } \ + } +#define VARITH(suffix, element) \ + VARITH_DO(add##suffix, +, element) \ + VARITH_DO(sub##suffix, -, element) +VARITH(ubm, u8) +VARITH(uhm, u16) +VARITH(uwm, u32) +#undef VARITH_DO +#undef VARITH + +#define VARITHFP(suffix, func) \ + void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ + HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \ + r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \ + } \ + } \ + } +VARITHFP(addfp, float32_add) +VARITHFP(subfp, float32_sub) +#undef VARITHFP + +#define VARITHSAT_CASE(type, op, cvt, element) \ + { \ + type result = (type)a->element[i] op (type)b->element[i]; \ + r->element[i] = cvt(result, &sat); \ + } + +#define VARITHSAT_DO(name, op, optype, cvt, element) \ + void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int sat = 0; \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + switch (sizeof(r->element[0])) { \ + case 1: \ + VARITHSAT_CASE(optype, op, cvt, element); \ + break; \ + case 2: \ + VARITHSAT_CASE(optype, op, cvt, element); \ + break; \ + case 4: \ + VARITHSAT_CASE(optype, op, cvt, element); \ + break; \ + } \ + } \ + if (sat) { \ + env->vscr |= (1 << VSCR_SAT); \ + } \ + } +#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \ + VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \ + VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element) +#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \ + VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \ + VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element) +VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb) +VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh) +VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw) +VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub) +VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh) +VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw) +#undef VARITHSAT_CASE +#undef VARITHSAT_DO +#undef VARITHSAT_SIGNED +#undef VARITHSAT_UNSIGNED + +#define VAVG_DO(name, element, etype) \ + void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \ + r->element[i] = x >> 1; \ + } \ + } + +#define VAVG(type, signed_element, signed_type, unsigned_element, \ + unsigned_type) \ + VAVG_DO(avgs##type, signed_element, signed_type) \ + VAVG_DO(avgu##type, unsigned_element, unsigned_type) +VAVG(b, s8, int16_t, u8, uint16_t) +VAVG(h, s16, int32_t, u16, uint32_t) +VAVG(w, s32, int64_t, u32, uint64_t) +#undef VAVG_DO +#undef VAVG + +#define VCF(suffix, cvt, element) \ + void helper_vcf##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \ + { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ + float32 t = cvt(b->element[i], &env->vec_status); \ + r->f[i] = float32_scalbn(t, -uim, &env->vec_status); \ + } \ + } +VCF(ux, uint32_to_float32, u32) +VCF(sx, int32_to_float32, s32) +#undef VCF + +#define VCMP_DO(suffix, compare, element, record) \ + void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + uint32_t ones = (uint32_t)-1; \ + uint32_t all = ones; \ + uint32_t none = 0; \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + uint32_t result = (a->element[i] compare b->element[i] ? \ + ones : 0x0); \ + switch (sizeof(a->element[0])) { \ + case 4: \ + r->u32[i] = result; \ + break; \ + case 2: \ + r->u16[i] = result; \ + break; \ + case 1: \ + r->u8[i] = result; \ + break; \ + } \ + all &= result; \ + none |= result; \ + } \ + if (record) { \ + env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \ + } \ + } +#define VCMP(suffix, compare, element) \ + VCMP_DO(suffix, compare, element, 0) \ + VCMP_DO(suffix##_dot, compare, element, 1) +VCMP(equb, ==, u8) +VCMP(equh, ==, u16) +VCMP(equw, ==, u32) +VCMP(gtub, >, u8) +VCMP(gtuh, >, u16) +VCMP(gtuw, >, u32) +VCMP(gtsb, >, s8) +VCMP(gtsh, >, s16) +VCMP(gtsw, >, s32) +#undef VCMP_DO +#undef VCMP + +#define VCMPFP_DO(suffix, compare, order, record) \ + void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + uint32_t ones = (uint32_t)-1; \ + uint32_t all = ones; \ + uint32_t none = 0; \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ + uint32_t result; \ + int rel = float32_compare_quiet(a->f[i], b->f[i], \ + &env->vec_status); \ + if (rel == float_relation_unordered) { \ + result = 0; \ + } else if (rel compare order) { \ + result = ones; \ + } else { \ + result = 0; \ + } \ + r->u32[i] = result; \ + all &= result; \ + none |= result; \ + } \ + if (record) { \ + env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \ + } \ + } +#define VCMPFP(suffix, compare, order) \ + VCMPFP_DO(suffix, compare, order, 0) \ + VCMPFP_DO(suffix##_dot, compare, order, 1) +VCMPFP(eqfp, ==, float_relation_equal) +VCMPFP(gefp, !=, float_relation_less) +VCMPFP(gtfp, ==, float_relation_greater) +#undef VCMPFP_DO +#undef VCMPFP + +static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, + int record) +{ + int i; + int all_in = 0; + + for (i = 0; i < ARRAY_SIZE(r->f); i++) { + int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); + if (le_rel == float_relation_unordered) { + r->u32[i] = 0xc0000000; + /* ALL_IN does not need to be updated here. */ + } else { + float32 bneg = float32_chs(b->f[i]); + int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status); + int le = le_rel != float_relation_greater; + int ge = ge_rel != float_relation_less; + + r->u32[i] = ((!le) << 31) | ((!ge) << 30); + all_in |= (!le | !ge); + } + } + if (record) { + env->crf[6] = (all_in == 0) << 1; + } +} + +void helper_vcmpbfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + vcmpbfp_internal(r, a, b, 0); +} + +void helper_vcmpbfp_dot(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + vcmpbfp_internal(r, a, b, 1); +} + +#define VCT(suffix, satcvt, element) \ + void helper_vct##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \ + { \ + int i; \ + int sat = 0; \ + float_status s = env->vec_status; \ + \ + set_float_rounding_mode(float_round_to_zero, &s); \ + for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ + if (float32_is_any_nan(b->f[i])) { \ + r->element[i] = 0; \ + } else { \ + float64 t = float32_to_float64(b->f[i], &s); \ + int64_t j; \ + \ + t = float64_scalbn(t, uim, &s); \ + j = float64_to_int64(t, &s); \ + r->element[i] = satcvt(j, &sat); \ + } \ + } \ + if (sat) { \ + env->vscr |= (1 << VSCR_SAT); \ + } \ + } +VCT(uxs, cvtsduw, u32) +VCT(sxs, cvtsdsw, s32) +#undef VCT + +void helper_vmaddfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(r->f); i++) { + HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) { + /* Need to do the computation in higher precision and round + * once at the end. */ + float64 af, bf, cf, t; + + af = float32_to_float64(a->f[i], &env->vec_status); + bf = float32_to_float64(b->f[i], &env->vec_status); + cf = float32_to_float64(c->f[i], &env->vec_status); + t = float64_mul(af, cf, &env->vec_status); + t = float64_add(t, bf, &env->vec_status); + r->f[i] = float64_to_float32(t, &env->vec_status); + } + } +} + +void helper_vmhaddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + int sat = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(r->s16); i++) { + int32_t prod = a->s16[i] * b->s16[i]; + int32_t t = (int32_t)c->s16[i] + (prod >> 15); + + r->s16[i] = cvtswsh(t, &sat); + } + + if (sat) { + env->vscr |= (1 << VSCR_SAT); + } +} + +void helper_vmhraddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + int sat = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(r->s16); i++) { + int32_t prod = a->s16[i] * b->s16[i] + 0x00004000; + int32_t t = (int32_t)c->s16[i] + (prod >> 15); + r->s16[i] = cvtswsh(t, &sat); + } + + if (sat) { + env->vscr |= (1 << VSCR_SAT); + } +} + +#define VMINMAX_DO(name, compare, element) \ + void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + if (a->element[i] compare b->element[i]) { \ + r->element[i] = b->element[i]; \ + } else { \ + r->element[i] = a->element[i]; \ + } \ + } \ + } +#define VMINMAX(suffix, element) \ + VMINMAX_DO(min##suffix, >, element) \ + VMINMAX_DO(max##suffix, <, element) +VMINMAX(sb, s8) +VMINMAX(sh, s16) +VMINMAX(sw, s32) +VMINMAX(ub, u8) +VMINMAX(uh, u16) +VMINMAX(uw, u32) +#undef VMINMAX_DO +#undef VMINMAX + +#define VMINMAXFP(suffix, rT, rF) \ + void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ + HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \ + if (float32_lt_quiet(a->f[i], b->f[i], \ + &env->vec_status)) { \ + r->f[i] = rT->f[i]; \ + } else { \ + r->f[i] = rF->f[i]; \ + } \ + } \ + } \ + } +VMINMAXFP(minfp, a, b) +VMINMAXFP(maxfp, b, a) +#undef VMINMAXFP + +void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(r->s16); i++) { + int32_t prod = a->s16[i] * b->s16[i]; + r->s16[i] = (int16_t) (prod + c->s16[i]); + } +} + +#define VMRG_DO(name, element, highp) \ + void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + ppc_avr_t result; \ + int i; \ + size_t n_elems = ARRAY_SIZE(r->element); \ + \ + for (i = 0; i < n_elems / 2; i++) { \ + if (highp) { \ + result.element[i*2+HI_IDX] = a->element[i]; \ + result.element[i*2+LO_IDX] = b->element[i]; \ + } else { \ + result.element[n_elems - i * 2 - (1 + HI_IDX)] = \ + b->element[n_elems - i - 1]; \ + result.element[n_elems - i * 2 - (1 + LO_IDX)] = \ + a->element[n_elems - i - 1]; \ + } \ + } \ + *r = result; \ + } +#if defined(HOST_WORDS_BIGENDIAN) +#define MRGHI 0 +#define MRGLO 1 +#else +#define MRGHI 1 +#define MRGLO 0 +#endif +#define VMRG(suffix, element) \ + VMRG_DO(mrgl##suffix, element, MRGHI) \ + VMRG_DO(mrgh##suffix, element, MRGLO) +VMRG(b, u8) +VMRG(h, u16) +VMRG(w, u32) +#undef VMRG_DO +#undef VMRG +#undef MRGHI +#undef MRGLO + +void helper_vmsummbm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + int32_t prod[16]; + int i; + + for (i = 0; i < ARRAY_SIZE(r->s8); i++) { + prod[i] = (int32_t)a->s8[i] * b->u8[i]; + } + + VECTOR_FOR_INORDER_I(i, s32) { + r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] + + prod[4 * i + 2] + prod[4 * i + 3]; + } +} + +void helper_vmsumshm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + int32_t prod[8]; + int i; + + for (i = 0; i < ARRAY_SIZE(r->s16); i++) { + prod[i] = a->s16[i] * b->s16[i]; + } + + VECTOR_FOR_INORDER_I(i, s32) { + r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1]; + } +} + +void helper_vmsumshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + int32_t prod[8]; + int i; + int sat = 0; + + for (i = 0; i < ARRAY_SIZE(r->s16); i++) { + prod[i] = (int32_t)a->s16[i] * b->s16[i]; + } + + VECTOR_FOR_INORDER_I(i, s32) { + int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1]; + + r->u32[i] = cvtsdsw(t, &sat); + } + + if (sat) { + env->vscr |= (1 << VSCR_SAT); + } +} + +void helper_vmsumubm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + uint16_t prod[16]; + int i; + + for (i = 0; i < ARRAY_SIZE(r->u8); i++) { + prod[i] = a->u8[i] * b->u8[i]; + } + + VECTOR_FOR_INORDER_I(i, u32) { + r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] + + prod[4 * i + 2] + prod[4 * i + 3]; + } +} + +void helper_vmsumuhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + uint32_t prod[8]; + int i; + + for (i = 0; i < ARRAY_SIZE(r->u16); i++) { + prod[i] = a->u16[i] * b->u16[i]; + } + + VECTOR_FOR_INORDER_I(i, u32) { + r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1]; + } +} + +void helper_vmsumuhs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + uint32_t prod[8]; + int i; + int sat = 0; + + for (i = 0; i < ARRAY_SIZE(r->u16); i++) { + prod[i] = a->u16[i] * b->u16[i]; + } + + VECTOR_FOR_INORDER_I(i, s32) { + uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1]; + + r->u32[i] = cvtuduw(t, &sat); + } + + if (sat) { + env->vscr |= (1 << VSCR_SAT); + } +} + +#define VMUL_DO(name, mul_element, prod_element, evenp) \ + void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int i; \ + \ + VECTOR_FOR_INORDER_I(i, prod_element) { \ + if (evenp) { \ + r->prod_element[i] = a->mul_element[i * 2 + HI_IDX] * \ + b->mul_element[i * 2 + HI_IDX]; \ + } else { \ + r->prod_element[i] = a->mul_element[i * 2 + LO_IDX] * \ + b->mul_element[i * 2 + LO_IDX]; \ + } \ + } \ + } +#define VMUL(suffix, mul_element, prod_element) \ + VMUL_DO(mule##suffix, mul_element, prod_element, 1) \ + VMUL_DO(mulo##suffix, mul_element, prod_element, 0) +VMUL(sb, s8, s16) +VMUL(sh, s16, s32) +VMUL(ub, u8, u16) +VMUL(uh, u16, u32) +#undef VMUL_DO +#undef VMUL + +void helper_vnmsubfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(r->f); i++) { + HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) { + /* Need to do the computation is higher precision and round + * once at the end. */ + float64 af, bf, cf, t; + + af = float32_to_float64(a->f[i], &env->vec_status); + bf = float32_to_float64(b->f[i], &env->vec_status); + cf = float32_to_float64(c->f[i], &env->vec_status); + t = float64_mul(af, cf, &env->vec_status); + t = float64_sub(t, bf, &env->vec_status); + t = float64_chs(t); + r->f[i] = float64_to_float32(t, &env->vec_status); + } + } +} + +void helper_vperm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + ppc_avr_t result; + int i; + + VECTOR_FOR_INORDER_I(i, u8) { + int s = c->u8[i] & 0x1f; +#if defined(HOST_WORDS_BIGENDIAN) + int index = s & 0xf; +#else + int index = 15 - (s & 0xf); +#endif + + if (s & 0x10) { + result.u8[i] = b->u8[index]; + } else { + result.u8[i] = a->u8[index]; + } + } + *r = result; +} + +#if defined(HOST_WORDS_BIGENDIAN) +#define PKBIG 1 +#else +#define PKBIG 0 +#endif +void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int i, j; + ppc_avr_t result; +#if defined(HOST_WORDS_BIGENDIAN) + const ppc_avr_t *x[2] = { a, b }; +#else + const ppc_avr_t *x[2] = { b, a }; +#endif + + VECTOR_FOR_INORDER_I(i, u64) { + VECTOR_FOR_INORDER_I(j, u32) { + uint32_t e = x[i]->u32[j]; + + result.u16[4*i+j] = (((e >> 9) & 0xfc00) | + ((e >> 6) & 0x3e0) | + ((e >> 3) & 0x1f)); + } + } + *r = result; +} + +#define VPK(suffix, from, to, cvt, dosat) \ + void helper_vpk##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int i; \ + int sat = 0; \ + ppc_avr_t result; \ + ppc_avr_t *a0 = PKBIG ? a : b; \ + ppc_avr_t *a1 = PKBIG ? b : a; \ + \ + VECTOR_FOR_INORDER_I(i, from) { \ + result.to[i] = cvt(a0->from[i], &sat); \ + result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \ + } \ + *r = result; \ + if (dosat && sat) { \ + env->vscr |= (1 << VSCR_SAT); \ + } \ + } +#define I(x, y) (x) +VPK(shss, s16, s8, cvtshsb, 1) +VPK(shus, s16, u8, cvtshub, 1) +VPK(swss, s32, s16, cvtswsh, 1) +VPK(swus, s32, u16, cvtswuh, 1) +VPK(uhus, u16, u8, cvtuhub, 1) +VPK(uwus, u32, u16, cvtuwuh, 1) +VPK(uhum, u16, u8, I, 0) +VPK(uwum, u32, u16, I, 0) +#undef I +#undef VPK +#undef PKBIG + +void helper_vrefp(ppc_avr_t *r, ppc_avr_t *b) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(r->f); i++) { + HANDLE_NAN1(r->f[i], b->f[i]) { + r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status); + } + } +} + +#define VRFI(suffix, rounding) \ + void helper_vrfi##suffix(ppc_avr_t *r, ppc_avr_t *b) \ + { \ + int i; \ + float_status s = env->vec_status; \ + \ + set_float_rounding_mode(rounding, &s); \ + for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ + HANDLE_NAN1(r->f[i], b->f[i]) { \ + r->f[i] = float32_round_to_int (b->f[i], &s); \ + } \ + } \ + } +VRFI(n, float_round_nearest_even) +VRFI(m, float_round_down) +VRFI(p, float_round_up) +VRFI(z, float_round_to_zero) +#undef VRFI + +#define VROTATE(suffix, element) \ + void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + unsigned int mask = ((1 << \ + (3 + (sizeof(a->element[0]) >> 1))) \ + - 1); \ + unsigned int shift = b->element[i] & mask; \ + r->element[i] = (a->element[i] << shift) | \ + (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \ + } \ + } +VROTATE(b, u8) +VROTATE(h, u16) +VROTATE(w, u32) +#undef VROTATE + +void helper_vrsqrtefp(ppc_avr_t *r, ppc_avr_t *b) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(r->f); i++) { + HANDLE_NAN1(r->f[i], b->f[i]) { + float32 t = float32_sqrt(b->f[i], &env->vec_status); + + r->f[i] = float32_div(float32_one, t, &env->vec_status); + } + } +} + +void helper_vsel(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +{ + r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]); + r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]); +} + +void helper_vexptefp(ppc_avr_t *r, ppc_avr_t *b) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(r->f); i++) { + HANDLE_NAN1(r->f[i], b->f[i]) { + r->f[i] = float32_exp2(b->f[i], &env->vec_status); + } + } +} + +void helper_vlogefp(ppc_avr_t *r, ppc_avr_t *b) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(r->f); i++) { + HANDLE_NAN1(r->f[i], b->f[i]) { + r->f[i] = float32_log2(b->f[i], &env->vec_status); + } + } +} + +#if defined(HOST_WORDS_BIGENDIAN) +#define LEFT 0 +#define RIGHT 1 +#else +#define LEFT 1 +#define RIGHT 0 +#endif +/* The specification says that the results are undefined if all of the + * shift counts are not identical. We check to make sure that they are + * to conform to what real hardware appears to do. */ +#define VSHIFT(suffix, leftp) \ + void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int shift = b->u8[LO_IDX*15] & 0x7; \ + int doit = 1; \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \ + doit = doit && ((b->u8[i] & 0x7) == shift); \ + } \ + if (doit) { \ + if (shift == 0) { \ + *r = *a; \ + } else if (leftp) { \ + uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \ + \ + r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \ + r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \ + } else { \ + uint64_t carry = a->u64[HI_IDX] << (64 - shift); \ + \ + r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \ + r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \ + } \ + } \ + } +VSHIFT(l, LEFT) +VSHIFT(r, RIGHT) +#undef VSHIFT +#undef LEFT +#undef RIGHT + +#define VSL(suffix, element) \ + void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + unsigned int mask = ((1 << \ + (3 + (sizeof(a->element[0]) >> 1))) \ + - 1); \ + unsigned int shift = b->element[i] & mask; \ + \ + r->element[i] = a->element[i] << shift; \ + } \ + } +VSL(b, u8) +VSL(h, u16) +VSL(w, u32) +#undef VSL + +void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift) +{ + int sh = shift & 0xf; + int i; + ppc_avr_t result; + +#if defined(HOST_WORDS_BIGENDIAN) + for (i = 0; i < ARRAY_SIZE(r->u8); i++) { + int index = sh + i; + if (index > 0xf) { + result.u8[i] = b->u8[index - 0x10]; + } else { + result.u8[i] = a->u8[index]; + } + } +#else + for (i = 0; i < ARRAY_SIZE(r->u8); i++) { + int index = (16 - sh) + i; + if (index > 0xf) { + result.u8[i] = a->u8[index - 0x10]; + } else { + result.u8[i] = b->u8[index]; + } + } +#endif + *r = result; +} + +void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf; + +#if defined(HOST_WORDS_BIGENDIAN) + memmove(&r->u8[0], &a->u8[sh], 16 - sh); + memset(&r->u8[16-sh], 0, sh); +#else + memmove(&r->u8[sh], &a->u8[0], 16 - sh); + memset(&r->u8[0], 0, sh); +#endif +} + +/* Experimental testing shows that hardware masks the immediate. */ +#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1)) +#if defined(HOST_WORDS_BIGENDIAN) +#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element) +#else +#define SPLAT_ELEMENT(element) \ + (ARRAY_SIZE(r->element) - 1 - _SPLAT_MASKED(element)) +#endif +#define VSPLT(suffix, element) \ + void helper_vsplt##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \ + { \ + uint32_t s = b->element[SPLAT_ELEMENT(element)]; \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + r->element[i] = s; \ + } \ + } +VSPLT(b, u8) +VSPLT(h, u16) +VSPLT(w, u32) +#undef VSPLT +#undef SPLAT_ELEMENT +#undef _SPLAT_MASKED + +#define VSPLTI(suffix, element, splat_type) \ + void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \ + { \ + splat_type x = (int8_t)(splat << 3) >> 3; \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + r->element[i] = x; \ + } \ + } +VSPLTI(b, s8, int8_t) +VSPLTI(h, s16, int16_t) +VSPLTI(w, s32, int32_t) +#undef VSPLTI + +#define VSR(suffix, element) \ + void helper_vsr##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + unsigned int mask = ((1 << \ + (3 + (sizeof(a->element[0]) >> 1))) \ + - 1); \ + unsigned int shift = b->element[i] & mask; \ + \ + r->element[i] = a->element[i] >> shift; \ + } \ + } +VSR(ab, s8) +VSR(ah, s16) +VSR(aw, s32) +VSR(b, u8) +VSR(h, u16) +VSR(w, u32) +#undef VSR + +void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int sh = (b->u8[LO_IDX * 0xf] >> 3) & 0xf; + +#if defined(HOST_WORDS_BIGENDIAN) + memmove(&r->u8[sh], &a->u8[0], 16 - sh); + memset(&r->u8[0], 0, sh); +#else + memmove(&r->u8[0], &a->u8[sh], 16 - sh); + memset(&r->u8[16 - sh], 0, sh); +#endif +} + +void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(r->u32); i++) { + r->u32[i] = a->u32[i] >= b->u32[i]; + } +} + +void helper_vsumsws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int64_t t; + int i, upper; + ppc_avr_t result; + int sat = 0; + +#if defined(HOST_WORDS_BIGENDIAN) + upper = ARRAY_SIZE(r->s32)-1; +#else + upper = 0; +#endif + t = (int64_t)b->s32[upper]; + for (i = 0; i < ARRAY_SIZE(r->s32); i++) { + t += a->s32[i]; + result.s32[i] = 0; + } + result.s32[upper] = cvtsdsw(t, &sat); + *r = result; + + if (sat) { + env->vscr |= (1 << VSCR_SAT); + } +} + +void helper_vsum2sws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int i, j, upper; + ppc_avr_t result; + int sat = 0; + +#if defined(HOST_WORDS_BIGENDIAN) + upper = 1; +#else + upper = 0; +#endif + for (i = 0; i < ARRAY_SIZE(r->u64); i++) { + int64_t t = (int64_t)b->s32[upper + i * 2]; + + result.u64[i] = 0; + for (j = 0; j < ARRAY_SIZE(r->u64); j++) { + t += a->s32[2 * i + j]; + } + result.s32[upper + i * 2] = cvtsdsw(t, &sat); + } + + *r = result; + if (sat) { + env->vscr |= (1 << VSCR_SAT); + } +} + +void helper_vsum4sbs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int i, j; + int sat = 0; + + for (i = 0; i < ARRAY_SIZE(r->s32); i++) { + int64_t t = (int64_t)b->s32[i]; + + for (j = 0; j < ARRAY_SIZE(r->s32); j++) { + t += a->s8[4 * i + j]; + } + r->s32[i] = cvtsdsw(t, &sat); + } + + if (sat) { + env->vscr |= (1 << VSCR_SAT); + } +} + +void helper_vsum4shs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int sat = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(r->s32); i++) { + int64_t t = (int64_t)b->s32[i]; + + t += a->s16[2 * i] + a->s16[2 * i + 1]; + r->s32[i] = cvtsdsw(t, &sat); + } + + if (sat) { + env->vscr |= (1 << VSCR_SAT); + } +} + +void helper_vsum4ubs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int i, j; + int sat = 0; + + for (i = 0; i < ARRAY_SIZE(r->u32); i++) { + uint64_t t = (uint64_t)b->u32[i]; + + for (j = 0; j < ARRAY_SIZE(r->u32); j++) { + t += a->u8[4 * i + j]; + } + r->u32[i] = cvtuduw(t, &sat); + } + + if (sat) { + env->vscr |= (1 << VSCR_SAT); + } +} + +#if defined(HOST_WORDS_BIGENDIAN) +#define UPKHI 1 +#define UPKLO 0 +#else +#define UPKHI 0 +#define UPKLO 1 +#endif +#define VUPKPX(suffix, hi) \ + void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \ + { \ + int i; \ + ppc_avr_t result; \ + \ + for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \ + uint16_t e = b->u16[hi ? i : i+4]; \ + uint8_t a = (e >> 15) ? 0xff : 0; \ + uint8_t r = (e >> 10) & 0x1f; \ + uint8_t g = (e >> 5) & 0x1f; \ + uint8_t b = e & 0x1f; \ + \ + result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \ + } \ + *r = result; \ + } +VUPKPX(lpx, UPKLO) +VUPKPX(hpx, UPKHI) +#undef VUPKPX + +#define VUPK(suffix, unpacked, packee, hi) \ + void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \ + { \ + int i; \ + ppc_avr_t result; \ + \ + if (hi) { \ + for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \ + result.unpacked[i] = b->packee[i]; \ + } \ + } else { \ + for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \ + i++) { \ + result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \ + } \ + } \ + *r = result; \ + } +VUPK(hsb, s16, s8, UPKHI) +VUPK(hsh, s32, s16, UPKHI) +VUPK(lsb, s16, s8, UPKLO) +VUPK(lsh, s32, s16, UPKLO) +#undef VUPK +#undef UPKHI +#undef UPKLO + +#undef DO_HANDLE_NAN +#undef HANDLE_NAN1 +#undef HANDLE_NAN2 +#undef HANDLE_NAN3 +#undef VECTOR_FOR_INORDER_I +#undef HI_IDX +#undef LO_IDX + +/*****************************************************************************/ +/* SPE extension helpers */ +/* Use a table to make this quicker */ +static uint8_t hbrev[16] = { + 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE, + 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF, +}; + +static inline uint8_t byte_reverse(uint8_t val) +{ + return hbrev[val >> 4] | (hbrev[val & 0xF] << 4); +} + +static inline uint32_t word_reverse(uint32_t val) +{ + return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) | + (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24); +} + +#define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */ +target_ulong helper_brinc(target_ulong arg1, target_ulong arg2) +{ + uint32_t a, b, d, mask; + + mask = UINT32_MAX >> (32 - MASKBITS); + a = arg1 & mask; + b = arg2 & mask; + d = word_reverse(1 + word_reverse(a | ~b)); + return (arg1 & ~mask) | (d & b); +} + +uint32_t helper_cntlsw32(uint32_t val) +{ + if (val & 0x80000000) { + return clz32(~val); + } else { + return clz32(val); + } +} + +uint32_t helper_cntlzw32(uint32_t val) +{ + return clz32(val); +} + +/* 440 specific */ +target_ulong helper_dlmzb(target_ulong high, target_ulong low, + uint32_t update_Rc) +{ + target_ulong mask; + int i; + + i = 1; + for (mask = 0xFF000000; mask != 0; mask = mask >> 8) { + if ((high & mask) == 0) { + if (update_Rc) { + env->crf[0] = 0x4; + } + goto done; + } + i++; + } + for (mask = 0xFF000000; mask != 0; mask = mask >> 8) { + if ((low & mask) == 0) { + if (update_Rc) { + env->crf[0] = 0x8; + } + goto done; + } + i++; + } + if (update_Rc) { + env->crf[0] = 0x2; + } + done: + env->xer = (env->xer & ~0x7F) | i; + if (update_Rc) { + env->crf[0] |= xer_so; + } + return i; +} diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 3f677f6da1..55b9e9dcb9 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -386,166 +386,6 @@ target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra, return i; } -/*****************************************************************************/ -/* Fixed point operations helpers */ -#if defined(TARGET_PPC64) - -/* multiply high word */ -uint64_t helper_mulhd(uint64_t arg1, uint64_t arg2) -{ - uint64_t tl, th; - - muls64(&tl, &th, arg1, arg2); - return th; -} - -/* multiply high word unsigned */ -uint64_t helper_mulhdu(uint64_t arg1, uint64_t arg2) -{ - uint64_t tl, th; - - mulu64(&tl, &th, arg1, arg2); - return th; -} - -uint64_t helper_mulldo(uint64_t arg1, uint64_t arg2) -{ - int64_t th; - uint64_t tl; - - muls64(&tl, (uint64_t *)&th, arg1, arg2); - /* If th != 0 && th != -1, then we had an overflow */ - if (likely((uint64_t)(th + 1) <= 1)) { - env->xer &= ~(1 << XER_OV); - } else { - env->xer |= (1 << XER_OV) | (1 << XER_SO); - } - return (int64_t)tl; -} -#endif - -target_ulong helper_cntlzw(target_ulong t) -{ - return clz32(t); -} - -#if defined(TARGET_PPC64) -target_ulong helper_cntlzd(target_ulong t) -{ - return clz64(t); -} -#endif - -/* shift right arithmetic helper */ -target_ulong helper_sraw(target_ulong value, target_ulong shift) -{ - int32_t ret; - - if (likely(!(shift & 0x20))) { - if (likely((uint32_t)shift != 0)) { - shift &= 0x1f; - ret = (int32_t)value >> shift; - if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) { - env->xer &= ~(1 << XER_CA); - } else { - env->xer |= (1 << XER_CA); - } - } else { - ret = (int32_t)value; - env->xer &= ~(1 << XER_CA); - } - } else { - ret = (int32_t)value >> 31; - if (ret) { - env->xer |= (1 << XER_CA); - } else { - env->xer &= ~(1 << XER_CA); - } - } - return (target_long)ret; -} - -#if defined(TARGET_PPC64) -target_ulong helper_srad(target_ulong value, target_ulong shift) -{ - int64_t ret; - - if (likely(!(shift & 0x40))) { - if (likely((uint64_t)shift != 0)) { - shift &= 0x3f; - ret = (int64_t)value >> shift; - if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) { - env->xer &= ~(1 << XER_CA); - } else { - env->xer |= (1 << XER_CA); - } - } else { - ret = (int64_t)value; - env->xer &= ~(1 << XER_CA); - } - } else { - ret = (int64_t)value >> 63; - if (ret) { - env->xer |= (1 << XER_CA); - } else { - env->xer &= ~(1 << XER_CA); - } - } - return ret; -} -#endif - -#if defined(TARGET_PPC64) -target_ulong helper_popcntb(target_ulong val) -{ - val = (val & 0x5555555555555555ULL) + ((val >> 1) & - 0x5555555555555555ULL); - val = (val & 0x3333333333333333ULL) + ((val >> 2) & - 0x3333333333333333ULL); - val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & - 0x0f0f0f0f0f0f0f0fULL); - return val; -} - -target_ulong helper_popcntw(target_ulong val) -{ - val = (val & 0x5555555555555555ULL) + ((val >> 1) & - 0x5555555555555555ULL); - val = (val & 0x3333333333333333ULL) + ((val >> 2) & - 0x3333333333333333ULL); - val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & - 0x0f0f0f0f0f0f0f0fULL); - val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) & - 0x00ff00ff00ff00ffULL); - val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) & - 0x0000ffff0000ffffULL); - return val; -} - -target_ulong helper_popcntd(target_ulong val) -{ - return ctpop64(val); -} -#else -target_ulong helper_popcntb(target_ulong val) -{ - val = (val & 0x55555555) + ((val >> 1) & 0x55555555); - val = (val & 0x33333333) + ((val >> 2) & 0x33333333); - val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f); - return val; -} - -target_ulong helper_popcntw(target_ulong val) -{ - val = (val & 0x55555555) + ((val >> 1) & 0x55555555); - val = (val & 0x33333333) + ((val >> 2) & 0x33333333); - val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f); - val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff); - val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff); - return val; -} -#endif - /*****************************************************************************/ /* PowerPC 601 specific instructions (POWER bridge) */ @@ -577,67 +417,6 @@ target_ulong helper_clcs(uint32_t arg) } } -target_ulong helper_div(target_ulong arg1, target_ulong arg2) -{ - uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ]; - - if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || - (int32_t)arg2 == 0) { - env->spr[SPR_MQ] = 0; - return INT32_MIN; - } else { - env->spr[SPR_MQ] = tmp % arg2; - return tmp / (int32_t)arg2; - } -} - -target_ulong helper_divo(target_ulong arg1, target_ulong arg2) -{ - uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ]; - - if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || - (int32_t)arg2 == 0) { - env->xer |= (1 << XER_OV) | (1 << XER_SO); - env->spr[SPR_MQ] = 0; - return INT32_MIN; - } else { - env->spr[SPR_MQ] = tmp % arg2; - tmp /= (int32_t)arg2; - if ((int32_t)tmp != tmp) { - env->xer |= (1 << XER_OV) | (1 << XER_SO); - } else { - env->xer &= ~(1 << XER_OV); - } - return tmp; - } -} - -target_ulong helper_divs(target_ulong arg1, target_ulong arg2) -{ - if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || - (int32_t)arg2 == 0) { - env->spr[SPR_MQ] = 0; - return INT32_MIN; - } else { - env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2; - return (int32_t)arg1 / (int32_t)arg2; - } -} - -target_ulong helper_divso(target_ulong arg1, target_ulong arg2) -{ - if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || - (int32_t)arg2 == 0) { - env->xer |= (1 << XER_OV) | (1 << XER_SO); - env->spr[SPR_MQ] = 0; - return INT32_MIN; - } else { - env->xer &= ~(1 << XER_OV); - env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2; - return (int32_t)arg1 / (int32_t)arg2; - } -} - #if !defined(CONFIG_USER_ONLY) target_ulong helper_rac(target_ulong addr) { @@ -659,26 +438,6 @@ target_ulong helper_rac(target_ulong addr) } #endif -/*****************************************************************************/ -/* 602 specific instructions */ -/* mfrom is the most crazy instruction ever seen, imho ! */ -/* Real implementation uses a ROM table. Do the same */ -/* Extremely decomposed: - * -arg / 256 - * return 256 * log10(10 + 1.0) + 0.5 - */ -#if !defined(CONFIG_USER_ONLY) -target_ulong helper_602_mfrom(target_ulong arg) -{ - if (likely(arg < 602)) { -#include "mfrom_table.c" - return mfrom_ROM_table[arg]; - } else { - return 0; - } -} -#endif - /*****************************************************************************/ /* Embedded PowerPC specific helpers */ @@ -716,43 +475,6 @@ void helper_store_dcr(target_ulong dcrn, target_ulong val) } } -/* 440 specific */ -target_ulong helper_dlmzb(target_ulong high, target_ulong low, - uint32_t update_Rc) -{ - target_ulong mask; - int i; - - i = 1; - for (mask = 0xFF000000; mask != 0; mask = mask >> 8) { - if ((high & mask) == 0) { - if (update_Rc) { - env->crf[0] = 0x4; - } - goto done; - } - i++; - } - for (mask = 0xFF000000; mask != 0; mask = mask >> 8) { - if ((low & mask) == 0) { - if (update_Rc) { - env->crf[0] = 0x8; - } - goto done; - } - i++; - } - if (update_Rc) { - env->crf[0] = 0x2; - } - done: - env->xer = (env->xer & ~0x7F) | i; - if (update_Rc) { - env->crf[0] |= xer_so; - } - return i; -} - /*****************************************************************************/ /* Altivec extension helpers */ #if defined(HOST_WORDS_BIGENDIAN) @@ -763,74 +485,6 @@ target_ulong helper_dlmzb(target_ulong high, target_ulong low, #define LO_IDX 0 #endif -#if defined(HOST_WORDS_BIGENDIAN) -#define VECTOR_FOR_INORDER_I(index, element) \ - for (index = 0; index < ARRAY_SIZE(r->element); index++) -#else -#define VECTOR_FOR_INORDER_I(index, element) \ - for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--) -#endif - -/* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise, - * execute the following block. */ -#define DO_HANDLE_NAN(result, x) \ - if (float32_is_any_nan(x)) { \ - CPU_FloatU __f; \ - __f.f = x; \ - __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \ - result = __f.f; \ - } else - -#define HANDLE_NAN1(result, x) \ - DO_HANDLE_NAN(result, x) -#define HANDLE_NAN2(result, x, y) \ - DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) -#define HANDLE_NAN3(result, x, y, z) \ - DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z) - -/* Saturating arithmetic helpers. */ -#define SATCVT(from, to, from_type, to_type, min, max) \ - static inline to_type cvt##from##to(from_type x, int *sat) \ - { \ - to_type r; \ - \ - if (x < (from_type)min) { \ - r = min; \ - *sat = 1; \ - } else if (x > (from_type)max) { \ - r = max; \ - *sat = 1; \ - } else { \ - r = x; \ - } \ - return r; \ - } -#define SATCVTU(from, to, from_type, to_type, min, max) \ - static inline to_type cvt##from##to(from_type x, int *sat) \ - { \ - to_type r; \ - \ - if (x > (from_type)max) { \ - r = max; \ - *sat = 1; \ - } else { \ - r = x; \ - } \ - return r; \ - } -SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX) -SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX) -SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX) - -SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX) -SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX) -SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX) -SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX) -SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX) -SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX) -#undef SATCVT -#undef SATCVTU - #define LVE(name, access, swap, element) \ void helper_##name(ppc_avr_t *r, target_ulong addr) \ { \ @@ -854,24 +508,6 @@ LVE(lvewx, ldl, bswap32, u32) #undef I #undef LVE -void helper_lvsl(ppc_avr_t *r, target_ulong sh) -{ - int i, j = (sh & 0xf); - - VECTOR_FOR_INORDER_I(i, u8) { - r->u8[i] = j++; - } -} - -void helper_lvsr(ppc_avr_t *r, target_ulong sh) -{ - int i, j = 0x10 - (sh & 0xf); - - VECTOR_FOR_INORDER_I(i, u8) { - r->u8[i] = j++; - } -} - #define STVE(name, access, swap, element) \ void helper_##name(ppc_avr_t *r, target_ulong addr) \ { \ @@ -893,1145 +529,9 @@ STVE(stvewx, stl, bswap32, u32) #undef I #undef LVE -void helper_mtvscr(ppc_avr_t *r) -{ -#if defined(HOST_WORDS_BIGENDIAN) - env->vscr = r->u32[3]; -#else - env->vscr = r->u32[0]; -#endif - set_flush_to_zero(vscr_nj, &env->vec_status); -} - -void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->u32); i++) { - r->u32[i] = ~a->u32[i] < b->u32[i]; - } -} - -#define VARITH_DO(name, op, element) \ - void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - r->element[i] = a->element[i] op b->element[i]; \ - } \ - } -#define VARITH(suffix, element) \ - VARITH_DO(add##suffix, +, element) \ - VARITH_DO(sub##suffix, -, element) -VARITH(ubm, u8) -VARITH(uhm, u16) -VARITH(uwm, u32) -#undef VARITH_DO -#undef VARITH - -#define VARITHFP(suffix, func) \ - void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \ - r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \ - } \ - } \ - } -VARITHFP(addfp, float32_add) -VARITHFP(subfp, float32_sub) -#undef VARITHFP - -#define VARITHSAT_CASE(type, op, cvt, element) \ - { \ - type result = (type)a->element[i] op (type)b->element[i]; \ - r->element[i] = cvt(result, &sat); \ - } - -#define VARITHSAT_DO(name, op, optype, cvt, element) \ - void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int sat = 0; \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - switch (sizeof(r->element[0])) { \ - case 1: \ - VARITHSAT_CASE(optype, op, cvt, element); \ - break; \ - case 2: \ - VARITHSAT_CASE(optype, op, cvt, element); \ - break; \ - case 4: \ - VARITHSAT_CASE(optype, op, cvt, element); \ - break; \ - } \ - } \ - if (sat) { \ - env->vscr |= (1 << VSCR_SAT); \ - } \ - } -#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \ - VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \ - VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element) -#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \ - VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \ - VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element) -VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb) -VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh) -VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw) -VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub) -VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh) -VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw) -#undef VARITHSAT_CASE -#undef VARITHSAT_DO -#undef VARITHSAT_SIGNED -#undef VARITHSAT_UNSIGNED - -#define VAVG_DO(name, element, etype) \ - void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \ - r->element[i] = x >> 1; \ - } \ - } - -#define VAVG(type, signed_element, signed_type, unsigned_element, \ - unsigned_type) \ - VAVG_DO(avgs##type, signed_element, signed_type) \ - VAVG_DO(avgu##type, unsigned_element, unsigned_type) -VAVG(b, s8, int16_t, u8, uint16_t) -VAVG(h, s16, int32_t, u16, uint32_t) -VAVG(w, s32, int64_t, u32, uint64_t) -#undef VAVG_DO -#undef VAVG - -#define VCF(suffix, cvt, element) \ - void helper_vcf##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - float32 t = cvt(b->element[i], &env->vec_status); \ - r->f[i] = float32_scalbn(t, -uim, &env->vec_status); \ - } \ - } -VCF(ux, uint32_to_float32, u32) -VCF(sx, int32_to_float32, s32) -#undef VCF - -#define VCMP_DO(suffix, compare, element, record) \ - void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - uint32_t ones = (uint32_t)-1; \ - uint32_t all = ones; \ - uint32_t none = 0; \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - uint32_t result = (a->element[i] compare b->element[i] ? \ - ones : 0x0); \ - switch (sizeof(a->element[0])) { \ - case 4: \ - r->u32[i] = result; \ - break; \ - case 2: \ - r->u16[i] = result; \ - break; \ - case 1: \ - r->u8[i] = result; \ - break; \ - } \ - all &= result; \ - none |= result; \ - } \ - if (record) { \ - env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \ - } \ - } -#define VCMP(suffix, compare, element) \ - VCMP_DO(suffix, compare, element, 0) \ - VCMP_DO(suffix##_dot, compare, element, 1) -VCMP(equb, ==, u8) -VCMP(equh, ==, u16) -VCMP(equw, ==, u32) -VCMP(gtub, >, u8) -VCMP(gtuh, >, u16) -VCMP(gtuw, >, u32) -VCMP(gtsb, >, s8) -VCMP(gtsh, >, s16) -VCMP(gtsw, >, s32) -#undef VCMP_DO -#undef VCMP - -#define VCMPFP_DO(suffix, compare, order, record) \ - void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - uint32_t ones = (uint32_t)-1; \ - uint32_t all = ones; \ - uint32_t none = 0; \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - uint32_t result; \ - int rel = float32_compare_quiet(a->f[i], b->f[i], \ - &env->vec_status); \ - if (rel == float_relation_unordered) { \ - result = 0; \ - } else if (rel compare order) { \ - result = ones; \ - } else { \ - result = 0; \ - } \ - r->u32[i] = result; \ - all &= result; \ - none |= result; \ - } \ - if (record) { \ - env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \ - } \ - } -#define VCMPFP(suffix, compare, order) \ - VCMPFP_DO(suffix, compare, order, 0) \ - VCMPFP_DO(suffix##_dot, compare, order, 1) -VCMPFP(eqfp, ==, float_relation_equal) -VCMPFP(gefp, !=, float_relation_less) -VCMPFP(gtfp, ==, float_relation_greater) -#undef VCMPFP_DO -#undef VCMPFP - -static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, - int record) -{ - int i; - int all_in = 0; - - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); - if (le_rel == float_relation_unordered) { - r->u32[i] = 0xc0000000; - /* ALL_IN does not need to be updated here. */ - } else { - float32 bneg = float32_chs(b->f[i]); - int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status); - int le = le_rel != float_relation_greater; - int ge = ge_rel != float_relation_less; - - r->u32[i] = ((!le) << 31) | ((!ge) << 30); - all_in |= (!le | !ge); - } - } - if (record) { - env->crf[6] = (all_in == 0) << 1; - } -} - -void helper_vcmpbfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - vcmpbfp_internal(r, a, b, 0); -} - -void helper_vcmpbfp_dot(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - vcmpbfp_internal(r, a, b, 1); -} - -#define VCT(suffix, satcvt, element) \ - void helper_vct##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \ - { \ - int i; \ - int sat = 0; \ - float_status s = env->vec_status; \ - \ - set_float_rounding_mode(float_round_to_zero, &s); \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - if (float32_is_any_nan(b->f[i])) { \ - r->element[i] = 0; \ - } else { \ - float64 t = float32_to_float64(b->f[i], &s); \ - int64_t j; \ - \ - t = float64_scalbn(t, uim, &s); \ - j = float64_to_int64(t, &s); \ - r->element[i] = satcvt(j, &sat); \ - } \ - } \ - if (sat) { \ - env->vscr |= (1 << VSCR_SAT); \ - } \ - } -VCT(uxs, cvtsduw, u32) -VCT(sxs, cvtsdsw, s32) -#undef VCT - -void helper_vmaddfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) { - /* Need to do the computation in higher precision and round - * once at the end. */ - float64 af, bf, cf, t; - - af = float32_to_float64(a->f[i], &env->vec_status); - bf = float32_to_float64(b->f[i], &env->vec_status); - cf = float32_to_float64(c->f[i], &env->vec_status); - t = float64_mul(af, cf, &env->vec_status); - t = float64_add(t, bf, &env->vec_status); - r->f[i] = float64_to_float32(t, &env->vec_status); - } - } -} - -void helper_vmhaddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - int sat = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(r->s16); i++) { - int32_t prod = a->s16[i] * b->s16[i]; - int32_t t = (int32_t)c->s16[i] + (prod >> 15); - - r->s16[i] = cvtswsh(t, &sat); - } - - if (sat) { - env->vscr |= (1 << VSCR_SAT); - } -} - -void helper_vmhraddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - int sat = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(r->s16); i++) { - int32_t prod = a->s16[i] * b->s16[i] + 0x00004000; - int32_t t = (int32_t)c->s16[i] + (prod >> 15); - r->s16[i] = cvtswsh(t, &sat); - } - - if (sat) { - env->vscr |= (1 << VSCR_SAT); - } -} - -#define VMINMAX_DO(name, compare, element) \ - void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - if (a->element[i] compare b->element[i]) { \ - r->element[i] = b->element[i]; \ - } else { \ - r->element[i] = a->element[i]; \ - } \ - } \ - } -#define VMINMAX(suffix, element) \ - VMINMAX_DO(min##suffix, >, element) \ - VMINMAX_DO(max##suffix, <, element) -VMINMAX(sb, s8) -VMINMAX(sh, s16) -VMINMAX(sw, s32) -VMINMAX(ub, u8) -VMINMAX(uh, u16) -VMINMAX(uw, u32) -#undef VMINMAX_DO -#undef VMINMAX - -#define VMINMAXFP(suffix, rT, rF) \ - void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \ - if (float32_lt_quiet(a->f[i], b->f[i], \ - &env->vec_status)) { \ - r->f[i] = rT->f[i]; \ - } else { \ - r->f[i] = rF->f[i]; \ - } \ - } \ - } \ - } -VMINMAXFP(minfp, a, b) -VMINMAXFP(maxfp, b, a) -#undef VMINMAXFP - -void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->s16); i++) { - int32_t prod = a->s16[i] * b->s16[i]; - r->s16[i] = (int16_t) (prod + c->s16[i]); - } -} - -#define VMRG_DO(name, element, highp) \ - void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - ppc_avr_t result; \ - int i; \ - size_t n_elems = ARRAY_SIZE(r->element); \ - \ - for (i = 0; i < n_elems / 2; i++) { \ - if (highp) { \ - result.element[i*2+HI_IDX] = a->element[i]; \ - result.element[i*2+LO_IDX] = b->element[i]; \ - } else { \ - result.element[n_elems - i * 2 - (1 + HI_IDX)] = \ - b->element[n_elems - i - 1]; \ - result.element[n_elems - i * 2 - (1 + LO_IDX)] = \ - a->element[n_elems - i - 1]; \ - } \ - } \ - *r = result; \ - } -#if defined(HOST_WORDS_BIGENDIAN) -#define MRGHI 0 -#define MRGLO 1 -#else -#define MRGHI 1 -#define MRGLO 0 -#endif -#define VMRG(suffix, element) \ - VMRG_DO(mrgl##suffix, element, MRGHI) \ - VMRG_DO(mrgh##suffix, element, MRGLO) -VMRG(b, u8) -VMRG(h, u16) -VMRG(w, u32) -#undef VMRG_DO -#undef VMRG -#undef MRGHI -#undef MRGLO - -void helper_vmsummbm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - int32_t prod[16]; - int i; - - for (i = 0; i < ARRAY_SIZE(r->s8); i++) { - prod[i] = (int32_t)a->s8[i] * b->u8[i]; - } - - VECTOR_FOR_INORDER_I(i, s32) { - r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] + - prod[4 * i + 2] + prod[4 * i + 3]; - } -} - -void helper_vmsumshm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - int32_t prod[8]; - int i; - - for (i = 0; i < ARRAY_SIZE(r->s16); i++) { - prod[i] = a->s16[i] * b->s16[i]; - } - - VECTOR_FOR_INORDER_I(i, s32) { - r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1]; - } -} - -void helper_vmsumshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - int32_t prod[8]; - int i; - int sat = 0; - - for (i = 0; i < ARRAY_SIZE(r->s16); i++) { - prod[i] = (int32_t)a->s16[i] * b->s16[i]; - } - - VECTOR_FOR_INORDER_I(i, s32) { - int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1]; - - r->u32[i] = cvtsdsw(t, &sat); - } - - if (sat) { - env->vscr |= (1 << VSCR_SAT); - } -} - -void helper_vmsumubm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - uint16_t prod[16]; - int i; - - for (i = 0; i < ARRAY_SIZE(r->u8); i++) { - prod[i] = a->u8[i] * b->u8[i]; - } - - VECTOR_FOR_INORDER_I(i, u32) { - r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] + - prod[4 * i + 2] + prod[4 * i + 3]; - } -} - -void helper_vmsumuhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - uint32_t prod[8]; - int i; - - for (i = 0; i < ARRAY_SIZE(r->u16); i++) { - prod[i] = a->u16[i] * b->u16[i]; - } - - VECTOR_FOR_INORDER_I(i, u32) { - r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1]; - } -} - -void helper_vmsumuhs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - uint32_t prod[8]; - int i; - int sat = 0; - - for (i = 0; i < ARRAY_SIZE(r->u16); i++) { - prod[i] = a->u16[i] * b->u16[i]; - } - - VECTOR_FOR_INORDER_I(i, s32) { - uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1]; - - r->u32[i] = cvtuduw(t, &sat); - } - - if (sat) { - env->vscr |= (1 << VSCR_SAT); - } -} - -#define VMUL_DO(name, mul_element, prod_element, evenp) \ - void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - \ - VECTOR_FOR_INORDER_I(i, prod_element) { \ - if (evenp) { \ - r->prod_element[i] = a->mul_element[i * 2 + HI_IDX] * \ - b->mul_element[i * 2 + HI_IDX]; \ - } else { \ - r->prod_element[i] = a->mul_element[i * 2 + LO_IDX] * \ - b->mul_element[i * 2 + LO_IDX]; \ - } \ - } \ - } -#define VMUL(suffix, mul_element, prod_element) \ - VMUL_DO(mule##suffix, mul_element, prod_element, 1) \ - VMUL_DO(mulo##suffix, mul_element, prod_element, 0) -VMUL(sb, s8, s16) -VMUL(sh, s16, s32) -VMUL(ub, u8, u16) -VMUL(uh, u16, u32) -#undef VMUL_DO -#undef VMUL - -void helper_vnmsubfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) { - /* Need to do the computation is higher precision and round - * once at the end. */ - float64 af, bf, cf, t; - - af = float32_to_float64(a->f[i], &env->vec_status); - bf = float32_to_float64(b->f[i], &env->vec_status); - cf = float32_to_float64(c->f[i], &env->vec_status); - t = float64_mul(af, cf, &env->vec_status); - t = float64_sub(t, bf, &env->vec_status); - t = float64_chs(t); - r->f[i] = float64_to_float32(t, &env->vec_status); - } - } -} - -void helper_vperm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - ppc_avr_t result; - int i; - - VECTOR_FOR_INORDER_I(i, u8) { - int s = c->u8[i] & 0x1f; -#if defined(HOST_WORDS_BIGENDIAN) - int index = s & 0xf; -#else - int index = 15 - (s & 0xf); -#endif - - if (s & 0x10) { - result.u8[i] = b->u8[index]; - } else { - result.u8[i] = a->u8[index]; - } - } - *r = result; -} - -#if defined(HOST_WORDS_BIGENDIAN) -#define PKBIG 1 -#else -#define PKBIG 0 -#endif -void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int i, j; - ppc_avr_t result; -#if defined(HOST_WORDS_BIGENDIAN) - const ppc_avr_t *x[2] = { a, b }; -#else - const ppc_avr_t *x[2] = { b, a }; -#endif - - VECTOR_FOR_INORDER_I(i, u64) { - VECTOR_FOR_INORDER_I(j, u32) { - uint32_t e = x[i]->u32[j]; - - result.u16[4*i+j] = (((e >> 9) & 0xfc00) | - ((e >> 6) & 0x3e0) | - ((e >> 3) & 0x1f)); - } - } - *r = result; -} - -#define VPK(suffix, from, to, cvt, dosat) \ - void helper_vpk##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - int sat = 0; \ - ppc_avr_t result; \ - ppc_avr_t *a0 = PKBIG ? a : b; \ - ppc_avr_t *a1 = PKBIG ? b : a; \ - \ - VECTOR_FOR_INORDER_I(i, from) { \ - result.to[i] = cvt(a0->from[i], &sat); \ - result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \ - } \ - *r = result; \ - if (dosat && sat) { \ - env->vscr |= (1 << VSCR_SAT); \ - } \ - } -#define I(x, y) (x) -VPK(shss, s16, s8, cvtshsb, 1) -VPK(shus, s16, u8, cvtshub, 1) -VPK(swss, s32, s16, cvtswsh, 1) -VPK(swus, s32, u16, cvtswuh, 1) -VPK(uhus, u16, u8, cvtuhub, 1) -VPK(uwus, u32, u16, cvtuwuh, 1) -VPK(uhum, u16, u8, I, 0) -VPK(uwum, u32, u16, I, 0) -#undef I -#undef VPK -#undef PKBIG - -void helper_vrefp(ppc_avr_t *r, ppc_avr_t *b) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN1(r->f[i], b->f[i]) { - r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status); - } - } -} - -#define VRFI(suffix, rounding) \ - void helper_vrfi##suffix(ppc_avr_t *r, ppc_avr_t *b) \ - { \ - int i; \ - float_status s = env->vec_status; \ - \ - set_float_rounding_mode(rounding, &s); \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - HANDLE_NAN1(r->f[i], b->f[i]) { \ - r->f[i] = float32_round_to_int (b->f[i], &s); \ - } \ - } \ - } -VRFI(n, float_round_nearest_even) -VRFI(m, float_round_down) -VRFI(p, float_round_up) -VRFI(z, float_round_to_zero) -#undef VRFI - -#define VROTATE(suffix, element) \ - void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - unsigned int mask = ((1 << \ - (3 + (sizeof(a->element[0]) >> 1))) \ - - 1); \ - unsigned int shift = b->element[i] & mask; \ - r->element[i] = (a->element[i] << shift) | \ - (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \ - } \ - } -VROTATE(b, u8) -VROTATE(h, u16) -VROTATE(w, u32) -#undef VROTATE - -void helper_vrsqrtefp(ppc_avr_t *r, ppc_avr_t *b) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN1(r->f[i], b->f[i]) { - float32 t = float32_sqrt(b->f[i], &env->vec_status); - - r->f[i] = float32_div(float32_one, t, &env->vec_status); - } - } -} - -void helper_vsel(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) -{ - r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]); - r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]); -} - -void helper_vexptefp(ppc_avr_t *r, ppc_avr_t *b) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN1(r->f[i], b->f[i]) { - r->f[i] = float32_exp2(b->f[i], &env->vec_status); - } - } -} - -void helper_vlogefp(ppc_avr_t *r, ppc_avr_t *b) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN1(r->f[i], b->f[i]) { - r->f[i] = float32_log2(b->f[i], &env->vec_status); - } - } -} - -#if defined(HOST_WORDS_BIGENDIAN) -#define LEFT 0 -#define RIGHT 1 -#else -#define LEFT 1 -#define RIGHT 0 -#endif -/* The specification says that the results are undefined if all of the - * shift counts are not identical. We check to make sure that they are - * to conform to what real hardware appears to do. */ -#define VSHIFT(suffix, leftp) \ - void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int shift = b->u8[LO_IDX*15] & 0x7; \ - int doit = 1; \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \ - doit = doit && ((b->u8[i] & 0x7) == shift); \ - } \ - if (doit) { \ - if (shift == 0) { \ - *r = *a; \ - } else if (leftp) { \ - uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \ - \ - r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \ - r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \ - } else { \ - uint64_t carry = a->u64[HI_IDX] << (64 - shift); \ - \ - r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \ - r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \ - } \ - } \ - } -VSHIFT(l, LEFT) -VSHIFT(r, RIGHT) -#undef VSHIFT -#undef LEFT -#undef RIGHT - -#define VSL(suffix, element) \ - void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - unsigned int mask = ((1 << \ - (3 + (sizeof(a->element[0]) >> 1))) \ - - 1); \ - unsigned int shift = b->element[i] & mask; \ - \ - r->element[i] = a->element[i] << shift; \ - } \ - } -VSL(b, u8) -VSL(h, u16) -VSL(w, u32) -#undef VSL - -void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift) -{ - int sh = shift & 0xf; - int i; - ppc_avr_t result; - -#if defined(HOST_WORDS_BIGENDIAN) - for (i = 0; i < ARRAY_SIZE(r->u8); i++) { - int index = sh + i; - if (index > 0xf) { - result.u8[i] = b->u8[index - 0x10]; - } else { - result.u8[i] = a->u8[index]; - } - } -#else - for (i = 0; i < ARRAY_SIZE(r->u8); i++) { - int index = (16 - sh) + i; - if (index > 0xf) { - result.u8[i] = a->u8[index - 0x10]; - } else { - result.u8[i] = b->u8[index]; - } - } -#endif - *r = result; -} - -void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf; - -#if defined(HOST_WORDS_BIGENDIAN) - memmove(&r->u8[0], &a->u8[sh], 16 - sh); - memset(&r->u8[16-sh], 0, sh); -#else - memmove(&r->u8[sh], &a->u8[0], 16 - sh); - memset(&r->u8[0], 0, sh); -#endif -} - -/* Experimental testing shows that hardware masks the immediate. */ -#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1)) -#if defined(HOST_WORDS_BIGENDIAN) -#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element) -#else -#define SPLAT_ELEMENT(element) \ - (ARRAY_SIZE(r->element) - 1 - _SPLAT_MASKED(element)) -#endif -#define VSPLT(suffix, element) \ - void helper_vsplt##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \ - { \ - uint32_t s = b->element[SPLAT_ELEMENT(element)]; \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - r->element[i] = s; \ - } \ - } -VSPLT(b, u8) -VSPLT(h, u16) -VSPLT(w, u32) -#undef VSPLT -#undef SPLAT_ELEMENT -#undef _SPLAT_MASKED - -#define VSPLTI(suffix, element, splat_type) \ - void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \ - { \ - splat_type x = (int8_t)(splat << 3) >> 3; \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - r->element[i] = x; \ - } \ - } -VSPLTI(b, s8, int8_t) -VSPLTI(h, s16, int16_t) -VSPLTI(w, s32, int32_t) -#undef VSPLTI - -#define VSR(suffix, element) \ - void helper_vsr##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - unsigned int mask = ((1 << \ - (3 + (sizeof(a->element[0]) >> 1))) \ - - 1); \ - unsigned int shift = b->element[i] & mask; \ - \ - r->element[i] = a->element[i] >> shift; \ - } \ - } -VSR(ab, s8) -VSR(ah, s16) -VSR(aw, s32) -VSR(b, u8) -VSR(h, u16) -VSR(w, u32) -#undef VSR - -void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int sh = (b->u8[LO_IDX * 0xf] >> 3) & 0xf; - -#if defined(HOST_WORDS_BIGENDIAN) - memmove(&r->u8[sh], &a->u8[0], 16 - sh); - memset(&r->u8[0], 0, sh); -#else - memmove(&r->u8[0], &a->u8[sh], 16 - sh); - memset(&r->u8[16 - sh], 0, sh); -#endif -} - -void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->u32); i++) { - r->u32[i] = a->u32[i] >= b->u32[i]; - } -} - -void helper_vsumsws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int64_t t; - int i, upper; - ppc_avr_t result; - int sat = 0; - -#if defined(HOST_WORDS_BIGENDIAN) - upper = ARRAY_SIZE(r->s32)-1; -#else - upper = 0; -#endif - t = (int64_t)b->s32[upper]; - for (i = 0; i < ARRAY_SIZE(r->s32); i++) { - t += a->s32[i]; - result.s32[i] = 0; - } - result.s32[upper] = cvtsdsw(t, &sat); - *r = result; - - if (sat) { - env->vscr |= (1 << VSCR_SAT); - } -} - -void helper_vsum2sws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int i, j, upper; - ppc_avr_t result; - int sat = 0; - -#if defined(HOST_WORDS_BIGENDIAN) - upper = 1; -#else - upper = 0; -#endif - for (i = 0; i < ARRAY_SIZE(r->u64); i++) { - int64_t t = (int64_t)b->s32[upper + i * 2]; - - result.u64[i] = 0; - for (j = 0; j < ARRAY_SIZE(r->u64); j++) { - t += a->s32[2 * i + j]; - } - result.s32[upper + i * 2] = cvtsdsw(t, &sat); - } - - *r = result; - if (sat) { - env->vscr |= (1 << VSCR_SAT); - } -} - -void helper_vsum4sbs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int i, j; - int sat = 0; - - for (i = 0; i < ARRAY_SIZE(r->s32); i++) { - int64_t t = (int64_t)b->s32[i]; - - for (j = 0; j < ARRAY_SIZE(r->s32); j++) { - t += a->s8[4 * i + j]; - } - r->s32[i] = cvtsdsw(t, &sat); - } - - if (sat) { - env->vscr |= (1 << VSCR_SAT); - } -} - -void helper_vsum4shs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int sat = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(r->s32); i++) { - int64_t t = (int64_t)b->s32[i]; - - t += a->s16[2 * i] + a->s16[2 * i + 1]; - r->s32[i] = cvtsdsw(t, &sat); - } - - if (sat) { - env->vscr |= (1 << VSCR_SAT); - } -} - -void helper_vsum4ubs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int i, j; - int sat = 0; - - for (i = 0; i < ARRAY_SIZE(r->u32); i++) { - uint64_t t = (uint64_t)b->u32[i]; - - for (j = 0; j < ARRAY_SIZE(r->u32); j++) { - t += a->u8[4 * i + j]; - } - r->u32[i] = cvtuduw(t, &sat); - } - - if (sat) { - env->vscr |= (1 << VSCR_SAT); - } -} - -#if defined(HOST_WORDS_BIGENDIAN) -#define UPKHI 1 -#define UPKLO 0 -#else -#define UPKHI 0 -#define UPKLO 1 -#endif -#define VUPKPX(suffix, hi) \ - void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \ - { \ - int i; \ - ppc_avr_t result; \ - \ - for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \ - uint16_t e = b->u16[hi ? i : i+4]; \ - uint8_t a = (e >> 15) ? 0xff : 0; \ - uint8_t r = (e >> 10) & 0x1f; \ - uint8_t g = (e >> 5) & 0x1f; \ - uint8_t b = e & 0x1f; \ - \ - result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \ - } \ - *r = result; \ - } -VUPKPX(lpx, UPKLO) -VUPKPX(hpx, UPKHI) -#undef VUPKPX - -#define VUPK(suffix, unpacked, packee, hi) \ - void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \ - { \ - int i; \ - ppc_avr_t result; \ - \ - if (hi) { \ - for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \ - result.unpacked[i] = b->packee[i]; \ - } \ - } else { \ - for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \ - i++) { \ - result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \ - } \ - } \ - *r = result; \ - } -VUPK(hsb, s16, s8, UPKHI) -VUPK(hsh, s32, s16, UPKHI) -VUPK(lsb, s16, s8, UPKLO) -VUPK(lsh, s32, s16, UPKLO) -#undef VUPK -#undef UPKHI -#undef UPKLO - -#undef DO_HANDLE_NAN -#undef HANDLE_NAN1 -#undef HANDLE_NAN2 -#undef HANDLE_NAN3 -#undef VECTOR_FOR_INORDER_I #undef HI_IDX #undef LO_IDX -/*****************************************************************************/ -/* SPE extension helpers */ -/* Use a table to make this quicker */ -static uint8_t hbrev[16] = { - 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE, - 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF, -}; - -static inline uint8_t byte_reverse(uint8_t val) -{ - return hbrev[val >> 4] | (hbrev[val & 0xF] << 4); -} - -static inline uint32_t word_reverse(uint32_t val) -{ - return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) | - (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24); -} - -#define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */ -target_ulong helper_brinc(target_ulong arg1, target_ulong arg2) -{ - uint32_t a, b, d, mask; - - mask = UINT32_MAX >> (32 - MASKBITS); - a = arg1 & mask; - b = arg2 & mask; - d = word_reverse(1 + word_reverse(a | ~b)); - return (arg1 & ~mask) | (d & b); -} - -uint32_t helper_cntlsw32(uint32_t val) -{ - if (val & 0x80000000) { - return clz32(~val); - } else { - return clz32(val); - } -} - -uint32_t helper_cntlzw32(uint32_t val) -{ - return clz32(val); -} - /*****************************************************************************/ /* Softmmu support */ #if !defined(CONFIG_USER_ONLY) From d15f74fb83fdaa80e8ef85001554d7fba0c1d0a3 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:29 +0000 Subject: [PATCH 09/72] ppc: Avoid AREG0 for integer and vector helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an explicit CPUPPCState parameter instead of relying on AREG0. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber [fix unwanted whitespace line in Makefile.target] Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 1 - target-ppc/helper.h | 176 +++++++++++++++++++-------------------- target-ppc/int_helper.c | 120 +++++++++++++++----------- target-ppc/translate.c | 174 ++++++++++++++++++++++++++------------ 4 files changed, 280 insertions(+), 191 deletions(-) diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 97e440be85..5d63400ce2 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -6,5 +6,4 @@ obj-y += excp_helper.o obj-y += fpu_helper.o obj-y += int_helper.o -$(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 0aba7f8e1a..7074bad859 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -33,17 +33,17 @@ DEF_HELPER_4(lscbx, tl, tl, i32, i32, i32) #if defined(TARGET_PPC64) DEF_HELPER_FLAGS_2(mulhd, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) DEF_HELPER_FLAGS_2(mulhdu, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) -DEF_HELPER_2(mulldo, i64, i64, i64) +DEF_HELPER_3(mulldo, i64, env, i64, i64) #endif DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) -DEF_HELPER_2(sraw, tl, tl, tl) +DEF_HELPER_3(sraw, tl, env, tl, tl) #if defined(TARGET_PPC64) DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) -DEF_HELPER_2(srad, tl, tl, tl) +DEF_HELPER_3(srad, tl, env, tl, tl) #endif DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) @@ -120,32 +120,32 @@ DEF_HELPER_3(vminuw, void, avr, avr, avr) DEF_HELPER_3(vmaxub, void, avr, avr, avr) DEF_HELPER_3(vmaxuh, void, avr, avr, avr) DEF_HELPER_3(vmaxuw, void, avr, avr, avr) -DEF_HELPER_3(vcmpequb, void, avr, avr, avr) -DEF_HELPER_3(vcmpequh, void, avr, avr, avr) -DEF_HELPER_3(vcmpequw, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtub, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtuh, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtuw, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtsb, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtsh, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtsw, void, avr, avr, avr) -DEF_HELPER_3(vcmpeqfp, void, avr, avr, avr) -DEF_HELPER_3(vcmpgefp, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtfp, void, avr, avr, avr) -DEF_HELPER_3(vcmpbfp, void, avr, avr, avr) -DEF_HELPER_3(vcmpequb_dot, void, avr, avr, avr) -DEF_HELPER_3(vcmpequh_dot, void, avr, avr, avr) -DEF_HELPER_3(vcmpequw_dot, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtub_dot, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtuh_dot, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtuw_dot, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtsb_dot, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtsh_dot, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtsw_dot, void, avr, avr, avr) -DEF_HELPER_3(vcmpeqfp_dot, void, avr, avr, avr) -DEF_HELPER_3(vcmpgefp_dot, void, avr, avr, avr) -DEF_HELPER_3(vcmpgtfp_dot, void, avr, avr, avr) -DEF_HELPER_3(vcmpbfp_dot, void, avr, avr, avr) +DEF_HELPER_4(vcmpequb, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpequh, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpequw, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtub, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtuh, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtuw, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtsb, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtsh, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtsw, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpeqfp, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgefp, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtfp, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpbfp, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpequb_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpequh_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpequw_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtub_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtuh_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtuw_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtsb_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtsh_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtsw_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpeqfp_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgefp_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpgtfp_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpbfp_dot, void, env, avr, avr, avr) DEF_HELPER_3(vmrglb, void, avr, avr, avr) DEF_HELPER_3(vmrglh, void, avr, avr, avr) DEF_HELPER_3(vmrglw, void, avr, avr, avr) @@ -175,18 +175,18 @@ DEF_HELPER_3(vaddcuw, void, avr, avr, avr) DEF_HELPER_3(vsubcuw, void, avr, avr, avr) DEF_HELPER_2(lvsl, void, avr, tl); DEF_HELPER_2(lvsr, void, avr, tl); -DEF_HELPER_3(vaddsbs, void, avr, avr, avr) -DEF_HELPER_3(vaddshs, void, avr, avr, avr) -DEF_HELPER_3(vaddsws, void, avr, avr, avr) -DEF_HELPER_3(vsubsbs, void, avr, avr, avr) -DEF_HELPER_3(vsubshs, void, avr, avr, avr) -DEF_HELPER_3(vsubsws, void, avr, avr, avr) -DEF_HELPER_3(vaddubs, void, avr, avr, avr) -DEF_HELPER_3(vadduhs, void, avr, avr, avr) -DEF_HELPER_3(vadduws, void, avr, avr, avr) -DEF_HELPER_3(vsububs, void, avr, avr, avr) -DEF_HELPER_3(vsubuhs, void, avr, avr, avr) -DEF_HELPER_3(vsubuws, void, avr, avr, avr) +DEF_HELPER_4(vaddsbs, void, env, avr, avr, avr) +DEF_HELPER_4(vaddshs, void, env, avr, avr, avr) +DEF_HELPER_4(vaddsws, void, env, avr, avr, avr) +DEF_HELPER_4(vsubsbs, void, env, avr, avr, avr) +DEF_HELPER_4(vsubshs, void, env, avr, avr, avr) +DEF_HELPER_4(vsubsws, void, env, avr, avr, avr) +DEF_HELPER_4(vaddubs, void, env, avr, avr, avr) +DEF_HELPER_4(vadduhs, void, env, avr, avr, avr) +DEF_HELPER_4(vadduws, void, env, avr, avr, avr) +DEF_HELPER_4(vsububs, void, env, avr, avr, avr) +DEF_HELPER_4(vsubuhs, void, env, avr, avr, avr) +DEF_HELPER_4(vsubuws, void, env, avr, avr, avr) DEF_HELPER_3(vrlb, void, avr, avr, avr) DEF_HELPER_3(vrlh, void, avr, avr, avr) DEF_HELPER_3(vrlw, void, avr, avr, avr) @@ -205,56 +205,56 @@ DEF_HELPER_2(vupkhsb, void, avr, avr) DEF_HELPER_2(vupkhsh, void, avr, avr) DEF_HELPER_2(vupklsb, void, avr, avr) DEF_HELPER_2(vupklsh, void, avr, avr) -DEF_HELPER_4(vmsumubm, void, avr, avr, avr, avr) -DEF_HELPER_4(vmsummbm, void, avr, avr, avr, avr) -DEF_HELPER_4(vsel, void, avr, avr, avr, avr) -DEF_HELPER_4(vperm, void, avr, avr, avr, avr) -DEF_HELPER_3(vpkshss, void, avr, avr, avr) -DEF_HELPER_3(vpkshus, void, avr, avr, avr) -DEF_HELPER_3(vpkswss, void, avr, avr, avr) -DEF_HELPER_3(vpkswus, void, avr, avr, avr) -DEF_HELPER_3(vpkuhus, void, avr, avr, avr) -DEF_HELPER_3(vpkuwus, void, avr, avr, avr) -DEF_HELPER_3(vpkuhum, void, avr, avr, avr) -DEF_HELPER_3(vpkuwum, void, avr, avr, avr) +DEF_HELPER_5(vmsumubm, void, env, avr, avr, avr, avr) +DEF_HELPER_5(vmsummbm, void, env, avr, avr, avr, avr) +DEF_HELPER_5(vsel, void, env, avr, avr, avr, avr) +DEF_HELPER_5(vperm, void, env, avr, avr, avr, avr) +DEF_HELPER_4(vpkshss, void, env, avr, avr, avr) +DEF_HELPER_4(vpkshus, void, env, avr, avr, avr) +DEF_HELPER_4(vpkswss, void, env, avr, avr, avr) +DEF_HELPER_4(vpkswus, void, env, avr, avr, avr) +DEF_HELPER_4(vpkuhus, void, env, avr, avr, avr) +DEF_HELPER_4(vpkuwus, void, env, avr, avr, avr) +DEF_HELPER_4(vpkuhum, void, env, avr, avr, avr) +DEF_HELPER_4(vpkuwum, void, env, avr, avr, avr) DEF_HELPER_3(vpkpx, void, avr, avr, avr) -DEF_HELPER_4(vmhaddshs, void, avr, avr, avr, avr) -DEF_HELPER_4(vmhraddshs, void, avr, avr, avr, avr) -DEF_HELPER_4(vmsumuhm, void, avr, avr, avr, avr) -DEF_HELPER_4(vmsumuhs, void, avr, avr, avr, avr) -DEF_HELPER_4(vmsumshm, void, avr, avr, avr, avr) -DEF_HELPER_4(vmsumshs, void, avr, avr, avr, avr) +DEF_HELPER_5(vmhaddshs, void, env, avr, avr, avr, avr) +DEF_HELPER_5(vmhraddshs, void, env, avr, avr, avr, avr) +DEF_HELPER_5(vmsumuhm, void, env, avr, avr, avr, avr) +DEF_HELPER_5(vmsumuhs, void, env, avr, avr, avr, avr) +DEF_HELPER_5(vmsumshm, void, env, avr, avr, avr, avr) +DEF_HELPER_5(vmsumshs, void, env, avr, avr, avr, avr) DEF_HELPER_4(vmladduhm, void, avr, avr, avr, avr) -DEF_HELPER_1(mtvscr, void, avr); +DEF_HELPER_2(mtvscr, void, env, avr); DEF_HELPER_2(lvebx, void, avr, tl) DEF_HELPER_2(lvehx, void, avr, tl) DEF_HELPER_2(lvewx, void, avr, tl) DEF_HELPER_2(stvebx, void, avr, tl) DEF_HELPER_2(stvehx, void, avr, tl) DEF_HELPER_2(stvewx, void, avr, tl) -DEF_HELPER_3(vsumsws, void, avr, avr, avr) -DEF_HELPER_3(vsum2sws, void, avr, avr, avr) -DEF_HELPER_3(vsum4sbs, void, avr, avr, avr) -DEF_HELPER_3(vsum4shs, void, avr, avr, avr) -DEF_HELPER_3(vsum4ubs, void, avr, avr, avr) -DEF_HELPER_3(vaddfp, void, avr, avr, avr) -DEF_HELPER_3(vsubfp, void, avr, avr, avr) -DEF_HELPER_3(vmaxfp, void, avr, avr, avr) -DEF_HELPER_3(vminfp, void, avr, avr, avr) -DEF_HELPER_2(vrefp, void, avr, avr) -DEF_HELPER_2(vrsqrtefp, void, avr, avr) -DEF_HELPER_4(vmaddfp, void, avr, avr, avr, avr) -DEF_HELPER_4(vnmsubfp, void, avr, avr, avr, avr) -DEF_HELPER_2(vexptefp, void, avr, avr) -DEF_HELPER_2(vlogefp, void, avr, avr) -DEF_HELPER_2(vrfim, void, avr, avr) -DEF_HELPER_2(vrfin, void, avr, avr) -DEF_HELPER_2(vrfip, void, avr, avr) -DEF_HELPER_2(vrfiz, void, avr, avr) -DEF_HELPER_3(vcfux, void, avr, avr, i32) -DEF_HELPER_3(vcfsx, void, avr, avr, i32) -DEF_HELPER_3(vctuxs, void, avr, avr, i32) -DEF_HELPER_3(vctsxs, void, avr, avr, i32) +DEF_HELPER_4(vsumsws, void, env, avr, avr, avr) +DEF_HELPER_4(vsum2sws, void, env, avr, avr, avr) +DEF_HELPER_4(vsum4sbs, void, env, avr, avr, avr) +DEF_HELPER_4(vsum4shs, void, env, avr, avr, avr) +DEF_HELPER_4(vsum4ubs, void, env, avr, avr, avr) +DEF_HELPER_4(vaddfp, void, env, avr, avr, avr) +DEF_HELPER_4(vsubfp, void, env, avr, avr, avr) +DEF_HELPER_4(vmaxfp, void, env, avr, avr, avr) +DEF_HELPER_4(vminfp, void, env, avr, avr, avr) +DEF_HELPER_3(vrefp, void, env, avr, avr) +DEF_HELPER_3(vrsqrtefp, void, env, avr, avr) +DEF_HELPER_5(vmaddfp, void, env, avr, avr, avr, avr) +DEF_HELPER_5(vnmsubfp, void, env, avr, avr, avr, avr) +DEF_HELPER_3(vexptefp, void, env, avr, avr) +DEF_HELPER_3(vlogefp, void, env, avr, avr) +DEF_HELPER_3(vrfim, void, env, avr, avr) +DEF_HELPER_3(vrfin, void, env, avr, avr) +DEF_HELPER_3(vrfip, void, env, avr, avr) +DEF_HELPER_3(vrfiz, void, env, avr, avr) +DEF_HELPER_4(vcfux, void, env, avr, avr, i32) +DEF_HELPER_4(vcfsx, void, env, avr, avr, i32) +DEF_HELPER_4(vctuxs, void, env, avr, avr, i32) +DEF_HELPER_4(vctsxs, void, env, avr, avr, i32) DEF_HELPER_2(efscfsi, i32, env, i32) DEF_HELPER_2(efscfui, i32, env, i32) @@ -362,15 +362,15 @@ DEF_HELPER_1(msgsnd, void, tl) DEF_HELPER_2(msgclr, void, env, tl) #endif -DEF_HELPER_3(dlmzb, tl, tl, tl, i32) +DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32) DEF_HELPER_FLAGS_1(clcs, TCG_CALL_CONST | TCG_CALL_PURE, tl, i32) #if !defined(CONFIG_USER_ONLY) DEF_HELPER_1(rac, tl, tl) #endif -DEF_HELPER_2(div, tl, tl, tl) -DEF_HELPER_2(divo, tl, tl, tl) -DEF_HELPER_2(divs, tl, tl, tl) -DEF_HELPER_2(divso, tl, tl, tl) +DEF_HELPER_3(div, tl, env, tl, tl) +DEF_HELPER_3(divo, tl, env, tl, tl) +DEF_HELPER_3(divs, tl, env, tl, tl) +DEF_HELPER_3(divso, tl, env, tl, tl) DEF_HELPER_1(load_dcr, tl, tl); DEF_HELPER_2(store_dcr, void, tl, tl) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 71c7304b57..3173f11294 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -17,7 +17,6 @@ * License along with this library; if not, see . */ #include "cpu.h" -#include "dyngen-exec.h" #include "host-utils.h" #include "helper.h" @@ -44,7 +43,7 @@ uint64_t helper_mulhdu(uint64_t arg1, uint64_t arg2) return th; } -uint64_t helper_mulldo(uint64_t arg1, uint64_t arg2) +uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, uint64_t arg2) { int64_t th; uint64_t tl; @@ -73,7 +72,8 @@ target_ulong helper_cntlzd(target_ulong t) #endif /* shift right arithmetic helper */ -target_ulong helper_sraw(target_ulong value, target_ulong shift) +target_ulong helper_sraw(CPUPPCState *env, target_ulong value, + target_ulong shift) { int32_t ret; @@ -102,7 +102,8 @@ target_ulong helper_sraw(target_ulong value, target_ulong shift) } #if defined(TARGET_PPC64) -target_ulong helper_srad(target_ulong value, target_ulong shift) +target_ulong helper_srad(CPUPPCState *env, target_ulong value, + target_ulong shift) { int64_t ret; @@ -184,7 +185,7 @@ target_ulong helper_popcntw(target_ulong val) /*****************************************************************************/ /* PowerPC 601 specific instructions (POWER bridge) */ -target_ulong helper_div(target_ulong arg1, target_ulong arg2) +target_ulong helper_div(CPUPPCState *env, target_ulong arg1, target_ulong arg2) { uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ]; @@ -198,7 +199,8 @@ target_ulong helper_div(target_ulong arg1, target_ulong arg2) } } -target_ulong helper_divo(target_ulong arg1, target_ulong arg2) +target_ulong helper_divo(CPUPPCState *env, target_ulong arg1, + target_ulong arg2) { uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ]; @@ -219,7 +221,8 @@ target_ulong helper_divo(target_ulong arg1, target_ulong arg2) } } -target_ulong helper_divs(target_ulong arg1, target_ulong arg2) +target_ulong helper_divs(CPUPPCState *env, target_ulong arg1, + target_ulong arg2) { if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || (int32_t)arg2 == 0) { @@ -231,7 +234,8 @@ target_ulong helper_divs(target_ulong arg1, target_ulong arg2) } } -target_ulong helper_divso(target_ulong arg1, target_ulong arg2) +target_ulong helper_divso(CPUPPCState *env, target_ulong arg1, + target_ulong arg2) { if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || (int32_t)arg2 == 0) { @@ -361,7 +365,7 @@ void helper_lvsr(ppc_avr_t *r, target_ulong sh) } } -void helper_mtvscr(ppc_avr_t *r) +void helper_mtvscr(CPUPPCState *env, ppc_avr_t *r) { #if defined(HOST_WORDS_BIGENDIAN) env->vscr = r->u32[3]; @@ -399,7 +403,8 @@ VARITH(uwm, u32) #undef VARITH #define VARITHFP(suffix, func) \ - void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \ + ppc_avr_t *b) \ { \ int i; \ \ @@ -420,7 +425,8 @@ VARITHFP(subfp, float32_sub) } #define VARITHSAT_DO(name, op, optype, cvt, element) \ - void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_v##name(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \ + ppc_avr_t *b) \ { \ int sat = 0; \ int i; \ @@ -481,7 +487,8 @@ VAVG(w, s32, int64_t, u32, uint64_t) #undef VAVG #define VCF(suffix, cvt, element) \ - void helper_vcf##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \ + void helper_vcf##suffix(CPUPPCState *env, ppc_avr_t *r, \ + ppc_avr_t *b, uint32_t uim) \ { \ int i; \ \ @@ -495,7 +502,8 @@ VCF(sx, int32_to_float32, s32) #undef VCF #define VCMP_DO(suffix, compare, element, record) \ - void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \ + ppc_avr_t *a, ppc_avr_t *b) \ { \ uint32_t ones = (uint32_t)-1; \ uint32_t all = ones; \ @@ -539,7 +547,8 @@ VCMP(gtsw, >, s32) #undef VCMP #define VCMPFP_DO(suffix, compare, order, record) \ - void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \ + ppc_avr_t *a, ppc_avr_t *b) \ { \ uint32_t ones = (uint32_t)-1; \ uint32_t all = ones; \ @@ -574,8 +583,8 @@ VCMPFP(gtfp, ==, float_relation_greater) #undef VCMPFP_DO #undef VCMPFP -static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, - int record) +static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r, + ppc_avr_t *a, ppc_avr_t *b, int record) { int i; int all_in = 0; @@ -600,18 +609,20 @@ static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, } } -void helper_vcmpbfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vcmpbfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { - vcmpbfp_internal(r, a, b, 0); + vcmpbfp_internal(env, r, a, b, 0); } -void helper_vcmpbfp_dot(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, + ppc_avr_t *b) { - vcmpbfp_internal(r, a, b, 1); + vcmpbfp_internal(env, r, a, b, 1); } #define VCT(suffix, satcvt, element) \ - void helper_vct##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \ + void helper_vct##suffix(CPUPPCState *env, ppc_avr_t *r, \ + ppc_avr_t *b, uint32_t uim) \ { \ int i; \ int sat = 0; \ @@ -638,7 +649,8 @@ VCT(uxs, cvtsduw, u32) VCT(sxs, cvtsdsw, s32) #undef VCT -void helper_vmaddfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmaddfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, + ppc_avr_t *c) { int i; @@ -658,7 +670,8 @@ void helper_vmaddfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vmhaddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, + ppc_avr_t *b, ppc_avr_t *c) { int sat = 0; int i; @@ -675,7 +688,8 @@ void helper_vmhaddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vmhraddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, + ppc_avr_t *b, ppc_avr_t *c) { int sat = 0; int i; @@ -717,7 +731,8 @@ VMINMAX(uw, u32) #undef VMINMAX #define VMINMAXFP(suffix, rT, rF) \ - void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \ + ppc_avr_t *b) \ { \ int i; \ \ @@ -784,7 +799,8 @@ VMRG(w, u32) #undef MRGHI #undef MRGLO -void helper_vmsummbm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, + ppc_avr_t *b, ppc_avr_t *c) { int32_t prod[16]; int i; @@ -799,7 +815,8 @@ void helper_vmsummbm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vmsumshm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, + ppc_avr_t *b, ppc_avr_t *c) { int32_t prod[8]; int i; @@ -813,7 +830,8 @@ void helper_vmsumshm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vmsumshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, + ppc_avr_t *b, ppc_avr_t *c) { int32_t prod[8]; int i; @@ -834,7 +852,8 @@ void helper_vmsumshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vmsumubm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, + ppc_avr_t *b, ppc_avr_t *c) { uint16_t prod[16]; int i; @@ -849,7 +868,8 @@ void helper_vmsumubm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vmsumuhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, + ppc_avr_t *b, ppc_avr_t *c) { uint32_t prod[8]; int i; @@ -863,7 +883,8 @@ void helper_vmsumuhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vmsumuhs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, + ppc_avr_t *b, ppc_avr_t *c) { uint32_t prod[8]; int i; @@ -909,7 +930,8 @@ VMUL(uh, u16, u32) #undef VMUL_DO #undef VMUL -void helper_vnmsubfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vnmsubfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, + ppc_avr_t *b, ppc_avr_t *c) { int i; @@ -930,7 +952,8 @@ void helper_vnmsubfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) } } -void helper_vperm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, + ppc_avr_t *c) { ppc_avr_t result; int i; @@ -980,7 +1003,8 @@ void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } #define VPK(suffix, from, to, cvt, dosat) \ - void helper_vpk##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + void helper_vpk##suffix(CPUPPCState *env, ppc_avr_t *r, \ + ppc_avr_t *a, ppc_avr_t *b) \ { \ int i; \ int sat = 0; \ @@ -1010,7 +1034,7 @@ VPK(uwum, u32, u16, I, 0) #undef VPK #undef PKBIG -void helper_vrefp(ppc_avr_t *r, ppc_avr_t *b) +void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) { int i; @@ -1022,7 +1046,8 @@ void helper_vrefp(ppc_avr_t *r, ppc_avr_t *b) } #define VRFI(suffix, rounding) \ - void helper_vrfi##suffix(ppc_avr_t *r, ppc_avr_t *b) \ + void helper_vrfi##suffix(CPUPPCState *env, ppc_avr_t *r, \ + ppc_avr_t *b) \ { \ int i; \ float_status s = env->vec_status; \ @@ -1059,7 +1084,7 @@ VROTATE(h, u16) VROTATE(w, u32) #undef VROTATE -void helper_vrsqrtefp(ppc_avr_t *r, ppc_avr_t *b) +void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) { int i; @@ -1072,13 +1097,14 @@ void helper_vrsqrtefp(ppc_avr_t *r, ppc_avr_t *b) } } -void helper_vsel(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_vsel(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, + ppc_avr_t *c) { r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]); r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]); } -void helper_vexptefp(ppc_avr_t *r, ppc_avr_t *b) +void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) { int i; @@ -1089,7 +1115,7 @@ void helper_vexptefp(ppc_avr_t *r, ppc_avr_t *b) } } -void helper_vlogefp(ppc_avr_t *r, ppc_avr_t *b) +void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) { int i; @@ -1286,7 +1312,7 @@ void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } } -void helper_vsumsws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vsumsws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int64_t t; int i, upper; @@ -1311,7 +1337,7 @@ void helper_vsumsws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } } -void helper_vsum2sws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vsum2sws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i, j, upper; ppc_avr_t result; @@ -1338,7 +1364,7 @@ void helper_vsum2sws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } } -void helper_vsum4sbs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vsum4sbs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i, j; int sat = 0; @@ -1357,7 +1383,7 @@ void helper_vsum4sbs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } } -void helper_vsum4shs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vsum4shs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int sat = 0; int i; @@ -1374,7 +1400,7 @@ void helper_vsum4shs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) } } -void helper_vsum4ubs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i, j; int sat = 0; @@ -1501,8 +1527,8 @@ uint32_t helper_cntlzw32(uint32_t val) } /* 440 specific */ -target_ulong helper_dlmzb(target_ulong high, target_ulong low, - uint32_t update_Rc) +target_ulong helper_dlmzb(CPUPPCState *env, target_ulong high, + target_ulong low, uint32_t update_Rc) { target_ulong mask; int i; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index c8b7982e0b..eb3cd5a792 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1181,8 +1181,16 @@ static void gen_mulld(DisasContext *ctx) if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } + /* mulldo mulldo. */ -GEN_INT_ARITH_MUL_HELPER(mulldo, 0x17); +static void gen_mulldo(DisasContext *ctx) +{ + gen_helper_mulldo(cpu_gpr[rD(ctx->opcode)], cpu_env, + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } +} #endif /* neg neg. nego nego. */ @@ -1869,7 +1877,7 @@ static void gen_slw(DisasContext *ctx) /* sraw & sraw. */ static void gen_sraw(DisasContext *ctx) { - gen_helper_sraw(cpu_gpr[rA(ctx->opcode)], + gen_helper_sraw(cpu_gpr[rA(ctx->opcode)], cpu_env, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); @@ -1953,7 +1961,7 @@ static void gen_sld(DisasContext *ctx) /* srad & srad. */ static void gen_srad(DisasContext *ctx) { - gen_helper_srad(cpu_gpr[rA(ctx->opcode)], + gen_helper_srad(cpu_gpr[rA(ctx->opcode)], cpu_env, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); @@ -4550,7 +4558,8 @@ static void gen_clcs(DisasContext *ctx) /* div - div. */ static void gen_div(DisasContext *ctx) { - gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rB(ctx->opcode)]); if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } @@ -4558,7 +4567,8 @@ static void gen_div(DisasContext *ctx) /* divo - divo. */ static void gen_divo(DisasContext *ctx) { - gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rB(ctx->opcode)]); if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } @@ -4566,7 +4576,8 @@ static void gen_divo(DisasContext *ctx) /* divs - divs. */ static void gen_divs(DisasContext *ctx) { - gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rB(ctx->opcode)]); if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } @@ -4574,7 +4585,8 @@ static void gen_divs(DisasContext *ctx) /* divso - divso. */ static void gen_divso(DisasContext *ctx) { - gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_env, + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } @@ -6237,8 +6249,8 @@ static void gen_wrteei(DisasContext *ctx) static void gen_dlmzb(DisasContext *ctx) { TCGv_i32 t0 = tcg_const_i32(Rc(ctx->opcode)); - gen_helper_dlmzb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], - cpu_gpr[rB(ctx->opcode)], t0); + gen_helper_dlmzb(cpu_gpr[rA(ctx->opcode)], cpu_env, + cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); tcg_temp_free_i32(t0); } @@ -6457,7 +6469,7 @@ static void gen_mtvscr(DisasContext *ctx) return; } p = gen_avr_ptr(rD(ctx->opcode)); - gen_helper_mtvscr(p); + gen_helper_mtvscr(cpu_env, p); tcg_temp_free_ptr(p); } @@ -6496,6 +6508,23 @@ static void glue(gen_, name)(DisasContext *ctx) tcg_temp_free_ptr(rd); \ } +#define GEN_VXFORM_ENV(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ +{ \ + TCGv_ptr ra, rb, rd; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + ra = gen_avr_ptr(rA(ctx->opcode)); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name(rd, cpu_env, ra, rb); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ +} + GEN_VXFORM(vaddubm, 0, 0); GEN_VXFORM(vadduhm, 0, 1); GEN_VXFORM(vadduwm, 0, 2); @@ -6547,41 +6576,41 @@ GEN_VXFORM(vslo, 6, 16); GEN_VXFORM(vsro, 6, 17); GEN_VXFORM(vaddcuw, 0, 6); GEN_VXFORM(vsubcuw, 0, 22); -GEN_VXFORM(vaddubs, 0, 8); -GEN_VXFORM(vadduhs, 0, 9); -GEN_VXFORM(vadduws, 0, 10); -GEN_VXFORM(vaddsbs, 0, 12); -GEN_VXFORM(vaddshs, 0, 13); -GEN_VXFORM(vaddsws, 0, 14); -GEN_VXFORM(vsububs, 0, 24); -GEN_VXFORM(vsubuhs, 0, 25); -GEN_VXFORM(vsubuws, 0, 26); -GEN_VXFORM(vsubsbs, 0, 28); -GEN_VXFORM(vsubshs, 0, 29); -GEN_VXFORM(vsubsws, 0, 30); +GEN_VXFORM_ENV(vaddubs, 0, 8); +GEN_VXFORM_ENV(vadduhs, 0, 9); +GEN_VXFORM_ENV(vadduws, 0, 10); +GEN_VXFORM_ENV(vaddsbs, 0, 12); +GEN_VXFORM_ENV(vaddshs, 0, 13); +GEN_VXFORM_ENV(vaddsws, 0, 14); +GEN_VXFORM_ENV(vsububs, 0, 24); +GEN_VXFORM_ENV(vsubuhs, 0, 25); +GEN_VXFORM_ENV(vsubuws, 0, 26); +GEN_VXFORM_ENV(vsubsbs, 0, 28); +GEN_VXFORM_ENV(vsubshs, 0, 29); +GEN_VXFORM_ENV(vsubsws, 0, 30); GEN_VXFORM(vrlb, 2, 0); GEN_VXFORM(vrlh, 2, 1); GEN_VXFORM(vrlw, 2, 2); GEN_VXFORM(vsl, 2, 7); GEN_VXFORM(vsr, 2, 11); -GEN_VXFORM(vpkuhum, 7, 0); -GEN_VXFORM(vpkuwum, 7, 1); -GEN_VXFORM(vpkuhus, 7, 2); -GEN_VXFORM(vpkuwus, 7, 3); -GEN_VXFORM(vpkshus, 7, 4); -GEN_VXFORM(vpkswus, 7, 5); -GEN_VXFORM(vpkshss, 7, 6); -GEN_VXFORM(vpkswss, 7, 7); +GEN_VXFORM_ENV(vpkuhum, 7, 0); +GEN_VXFORM_ENV(vpkuwum, 7, 1); +GEN_VXFORM_ENV(vpkuhus, 7, 2); +GEN_VXFORM_ENV(vpkuwus, 7, 3); +GEN_VXFORM_ENV(vpkshus, 7, 4); +GEN_VXFORM_ENV(vpkswus, 7, 5); +GEN_VXFORM_ENV(vpkshss, 7, 6); +GEN_VXFORM_ENV(vpkswss, 7, 7); GEN_VXFORM(vpkpx, 7, 12); -GEN_VXFORM(vsum4ubs, 4, 24); -GEN_VXFORM(vsum4sbs, 4, 28); -GEN_VXFORM(vsum4shs, 4, 25); -GEN_VXFORM(vsum2sws, 4, 26); -GEN_VXFORM(vsumsws, 4, 30); -GEN_VXFORM(vaddfp, 5, 0); -GEN_VXFORM(vsubfp, 5, 1); -GEN_VXFORM(vmaxfp, 5, 16); -GEN_VXFORM(vminfp, 5, 17); +GEN_VXFORM_ENV(vsum4ubs, 4, 24); +GEN_VXFORM_ENV(vsum4sbs, 4, 28); +GEN_VXFORM_ENV(vsum4shs, 4, 25); +GEN_VXFORM_ENV(vsum2sws, 4, 26); +GEN_VXFORM_ENV(vsumsws, 4, 30); +GEN_VXFORM_ENV(vaddfp, 5, 0); +GEN_VXFORM_ENV(vsubfp, 5, 1); +GEN_VXFORM_ENV(vmaxfp, 5, 16); +GEN_VXFORM_ENV(vminfp, 5, 17); #define GEN_VXRFORM1(opname, name, str, opc2, opc3) \ static void glue(gen_, name)(DisasContext *ctx) \ @@ -6594,7 +6623,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ ra = gen_avr_ptr(rA(ctx->opcode)); \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##opname (rd, ra, rb); \ + gen_helper_##opname(cpu_env, rd, ra, rb); \ tcg_temp_free_ptr(ra); \ tcg_temp_free_ptr(rb); \ tcg_temp_free_ptr(rd); \ @@ -6653,20 +6682,36 @@ static void glue(gen_, name)(DisasContext *ctx) tcg_temp_free_ptr(rd); \ } +#define GEN_VXFORM_NOA_ENV(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb, rd; \ + \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name(cpu_env, rd, rb); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + } + GEN_VXFORM_NOA(vupkhsb, 7, 8); GEN_VXFORM_NOA(vupkhsh, 7, 9); GEN_VXFORM_NOA(vupklsb, 7, 10); GEN_VXFORM_NOA(vupklsh, 7, 11); GEN_VXFORM_NOA(vupkhpx, 7, 13); GEN_VXFORM_NOA(vupklpx, 7, 15); -GEN_VXFORM_NOA(vrefp, 5, 4); -GEN_VXFORM_NOA(vrsqrtefp, 5, 5); -GEN_VXFORM_NOA(vexptefp, 5, 6); -GEN_VXFORM_NOA(vlogefp, 5, 7); -GEN_VXFORM_NOA(vrfim, 5, 8); -GEN_VXFORM_NOA(vrfin, 5, 9); -GEN_VXFORM_NOA(vrfip, 5, 10); -GEN_VXFORM_NOA(vrfiz, 5, 11); +GEN_VXFORM_NOA_ENV(vrefp, 5, 4); +GEN_VXFORM_NOA_ENV(vrsqrtefp, 5, 5); +GEN_VXFORM_NOA_ENV(vexptefp, 5, 6); +GEN_VXFORM_NOA_ENV(vlogefp, 5, 7); +GEN_VXFORM_NOA_ENV(vrfim, 5, 8); +GEN_VXFORM_NOA_ENV(vrfin, 5, 9); +GEN_VXFORM_NOA_ENV(vrfip, 5, 10); +GEN_VXFORM_NOA_ENV(vrfiz, 5, 11); #define GEN_VXFORM_SIMM(name, opc2, opc3) \ static void glue(gen_, name)(DisasContext *ctx) \ @@ -6702,13 +6747,32 @@ static void glue(gen_, name)(DisasContext *ctx) tcg_temp_free_ptr(rd); \ } +#define GEN_VXFORM_UIMM_ENV(name, opc2, opc3) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb, rd; \ + TCGv_i32 uimm; \ + \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + uimm = tcg_const_i32(UIMM5(ctx->opcode)); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name(cpu_env, rd, rb, uimm); \ + tcg_temp_free_i32(uimm); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + } + GEN_VXFORM_UIMM(vspltb, 6, 8); GEN_VXFORM_UIMM(vsplth, 6, 9); GEN_VXFORM_UIMM(vspltw, 6, 10); -GEN_VXFORM_UIMM(vcfux, 5, 12); -GEN_VXFORM_UIMM(vcfsx, 5, 13); -GEN_VXFORM_UIMM(vctuxs, 5, 14); -GEN_VXFORM_UIMM(vctsxs, 5, 15); +GEN_VXFORM_UIMM_ENV(vcfux, 5, 12); +GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13); +GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14); +GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15); static void gen_vsldoi(DisasContext *ctx) { @@ -6730,7 +6794,7 @@ static void gen_vsldoi(DisasContext *ctx) } #define GEN_VAFORM_PAIRED(name0, name1, opc2) \ -static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ +static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ { \ TCGv_ptr ra, rb, rc, rd; \ if (unlikely(!ctx->altivec_enabled)) { \ @@ -6742,9 +6806,9 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx) rc = gen_avr_ptr(rC(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ if (Rc(ctx->opcode)) { \ - gen_helper_##name1 (rd, ra, rb, rc); \ + gen_helper_##name1(cpu_env, rd, ra, rb, rc); \ } else { \ - gen_helper_##name0 (rd, ra, rb, rc); \ + gen_helper_##name0(cpu_env, rd, ra, rb, rc); \ } \ tcg_temp_free_ptr(ra); \ tcg_temp_free_ptr(rb); \ From ec19c4d14643a38890745d46535d3149fec2033f Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:30 +0000 Subject: [PATCH 10/72] ppc: Split MMU etc. helpers from op_helper.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move MMU, TLB, SLB and BAT ops to mmu_helper.c. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 2 + target-ppc/mmu_helper.c | 882 +++++++++++++++++++++++++++++++++++++++ target-ppc/op_helper.c | 854 ------------------------------------- 3 files changed, 884 insertions(+), 854 deletions(-) create mode 100644 target-ppc/mmu_helper.c diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 5d63400ce2..0f89c2c53a 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -5,5 +5,7 @@ obj-y += op_helper.o helper.o obj-y += excp_helper.o obj-y += fpu_helper.o obj-y += int_helper.o +obj-y += mmu_helper.o +$(obj)/mmu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c new file mode 100644 index 0000000000..81800b618f --- /dev/null +++ b/target-ppc/mmu_helper.c @@ -0,0 +1,882 @@ +/* + * PowerPC MMU, TLB, SLB and BAT emulation 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, see . + */ +#include "cpu.h" +#include "dyngen-exec.h" +#include "helper.h" + +//#define DEBUG_SOFTWARE_TLB + +#ifdef DEBUG_SOFTWARE_TLB +# define LOG_SWTLB(...) qemu_log(__VA_ARGS__) +#else +# define LOG_SWTLB(...) do { } while (0) +#endif + +/*****************************************************************************/ +/* SPR accesses */ + +#if !defined(CONFIG_USER_ONLY) +void helper_store_ibatu(uint32_t nr, target_ulong val) +{ + ppc_store_ibatu(env, nr, val); +} + +void helper_store_ibatl(uint32_t nr, target_ulong val) +{ + ppc_store_ibatl(env, nr, val); +} + +void helper_store_dbatu(uint32_t nr, target_ulong val) +{ + ppc_store_dbatu(env, nr, val); +} + +void helper_store_dbatl(uint32_t nr, target_ulong val) +{ + ppc_store_dbatl(env, nr, val); +} + +void helper_store_601_batl(uint32_t nr, target_ulong val) +{ + ppc_store_ibatl_601(env, nr, val); +} + +void helper_store_601_batu(uint32_t nr, target_ulong val) +{ + ppc_store_ibatu_601(env, nr, val); +} + +/* Segment registers load and store */ +target_ulong helper_load_sr(target_ulong sr_num) +{ +#if defined(TARGET_PPC64) + if (env->mmu_model & POWERPC_MMU_64) { + return ppc_load_sr(env, sr_num); + } +#endif + return env->sr[sr_num]; +} + +void helper_store_sr(target_ulong sr_num, target_ulong val) +{ + ppc_store_sr(env, sr_num, val); +} + +/* SLB management */ +#if defined(TARGET_PPC64) +void helper_store_slb(target_ulong rb, target_ulong rs) +{ + if (ppc_store_slb(env, rb, rs) < 0) { + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL); + } +} + +target_ulong helper_load_slb_esid(target_ulong rb) +{ + target_ulong rt; + + if (ppc_load_slb_esid(env, rb, &rt) < 0) { + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL); + } + return rt; +} + +target_ulong helper_load_slb_vsid(target_ulong rb) +{ + target_ulong rt; + + if (ppc_load_slb_vsid(env, rb, &rt) < 0) { + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL); + } + return rt; +} + +void helper_slbia(void) +{ + ppc_slb_invalidate_all(env); +} + +void helper_slbie(target_ulong addr) +{ + ppc_slb_invalidate_one(env, addr); +} + +#endif /* defined(TARGET_PPC64) */ + +/* TLB management */ +void helper_tlbia(void) +{ + ppc_tlb_invalidate_all(env); +} + +void helper_tlbie(target_ulong addr) +{ + ppc_tlb_invalidate_one(env, addr); +} + +/* Software driven TLBs management */ +/* PowerPC 602/603 software TLB load instructions helpers */ +static void do_6xx_tlb(target_ulong new_EPN, int is_code) +{ + target_ulong RPN, CMP, EPN; + int way; + + RPN = env->spr[SPR_RPA]; + if (is_code) { + CMP = env->spr[SPR_ICMP]; + EPN = env->spr[SPR_IMISS]; + } else { + CMP = env->spr[SPR_DCMP]; + EPN = env->spr[SPR_DMISS]; + } + way = (env->spr[SPR_SRR1] >> 17) & 1; + (void)EPN; /* avoid a compiler warning */ + LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx + " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP, + RPN, way); + /* Store this TLB */ + ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK), + way, is_code, CMP, RPN); +} + +void helper_6xx_tlbd(target_ulong EPN) +{ + do_6xx_tlb(EPN, 0); +} + +void helper_6xx_tlbi(target_ulong EPN) +{ + do_6xx_tlb(EPN, 1); +} + +/* PowerPC 74xx software TLB load instructions helpers */ +static void do_74xx_tlb(target_ulong new_EPN, int is_code) +{ + target_ulong RPN, CMP, EPN; + int way; + + RPN = env->spr[SPR_PTELO]; + CMP = env->spr[SPR_PTEHI]; + EPN = env->spr[SPR_TLBMISS] & ~0x3; + way = env->spr[SPR_TLBMISS] & 0x3; + (void)EPN; /* avoid a compiler warning */ + LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx + " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP, + RPN, way); + /* Store this TLB */ + ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK), + way, is_code, CMP, RPN); +} + +void helper_74xx_tlbd(target_ulong EPN) +{ + do_74xx_tlb(EPN, 0); +} + +void helper_74xx_tlbi(target_ulong EPN) +{ + do_74xx_tlb(EPN, 1); +} + +/*****************************************************************************/ +/* PowerPC 601 specific instructions (POWER bridge) */ + +target_ulong helper_rac(target_ulong addr) +{ + mmu_ctx_t ctx; + int nb_BATs; + target_ulong ret = 0; + + /* We don't have to generate many instances of this instruction, + * as rac is supervisor only. + */ + /* XXX: FIX THIS: Pretend we have no BAT */ + nb_BATs = env->nb_BATs; + env->nb_BATs = 0; + if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) { + ret = ctx.raddr; + } + env->nb_BATs = nb_BATs; + return ret; +} + +static inline target_ulong booke_tlb_to_page_size(int size) +{ + return 1024 << (2 * size); +} + +static inline int booke_page_size_to_tlb(target_ulong page_size) +{ + int size; + + switch (page_size) { + case 0x00000400UL: + size = 0x0; + break; + case 0x00001000UL: + size = 0x1; + break; + case 0x00004000UL: + size = 0x2; + break; + case 0x00010000UL: + size = 0x3; + break; + case 0x00040000UL: + size = 0x4; + break; + case 0x00100000UL: + size = 0x5; + break; + case 0x00400000UL: + size = 0x6; + break; + case 0x01000000UL: + size = 0x7; + break; + case 0x04000000UL: + size = 0x8; + break; + case 0x10000000UL: + size = 0x9; + break; + case 0x40000000UL: + size = 0xA; + break; +#if defined(TARGET_PPC64) + case 0x000100000000ULL: + size = 0xB; + break; + case 0x000400000000ULL: + size = 0xC; + break; + case 0x001000000000ULL: + size = 0xD; + break; + case 0x004000000000ULL: + size = 0xE; + break; + case 0x010000000000ULL: + size = 0xF; + break; +#endif + default: + size = -1; + break; + } + + return size; +} + +/* Helpers for 4xx TLB management */ +#define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */ + +#define PPC4XX_TLBHI_V 0x00000040 +#define PPC4XX_TLBHI_E 0x00000020 +#define PPC4XX_TLBHI_SIZE_MIN 0 +#define PPC4XX_TLBHI_SIZE_MAX 7 +#define PPC4XX_TLBHI_SIZE_DEFAULT 1 +#define PPC4XX_TLBHI_SIZE_SHIFT 7 +#define PPC4XX_TLBHI_SIZE_MASK 0x00000007 + +#define PPC4XX_TLBLO_EX 0x00000200 +#define PPC4XX_TLBLO_WR 0x00000100 +#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF +#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00 + +target_ulong helper_4xx_tlbre_hi(target_ulong entry) +{ + ppcemb_tlb_t *tlb; + target_ulong ret; + int size; + + entry &= PPC4XX_TLB_ENTRY_MASK; + tlb = &env->tlb.tlbe[entry]; + ret = tlb->EPN; + if (tlb->prot & PAGE_VALID) { + ret |= PPC4XX_TLBHI_V; + } + size = booke_page_size_to_tlb(tlb->size); + if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) { + size = PPC4XX_TLBHI_SIZE_DEFAULT; + } + ret |= size << PPC4XX_TLBHI_SIZE_SHIFT; + env->spr[SPR_40x_PID] = tlb->PID; + return ret; +} + +target_ulong helper_4xx_tlbre_lo(target_ulong entry) +{ + ppcemb_tlb_t *tlb; + target_ulong ret; + + entry &= PPC4XX_TLB_ENTRY_MASK; + tlb = &env->tlb.tlbe[entry]; + ret = tlb->RPN; + if (tlb->prot & PAGE_EXEC) { + ret |= PPC4XX_TLBLO_EX; + } + if (tlb->prot & PAGE_WRITE) { + ret |= PPC4XX_TLBLO_WR; + } + return ret; +} + +void helper_4xx_tlbwe_hi(target_ulong entry, target_ulong val) +{ + ppcemb_tlb_t *tlb; + target_ulong page, end; + + LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry, + val); + entry &= PPC4XX_TLB_ENTRY_MASK; + tlb = &env->tlb.tlbe[entry]; + /* Invalidate previous TLB (if it's valid) */ + if (tlb->prot & PAGE_VALID) { + end = tlb->EPN + tlb->size; + LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end " + TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end); + for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { + tlb_flush_page(env, page); + } + } + tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT) + & PPC4XX_TLBHI_SIZE_MASK); + /* We cannot handle TLB size < TARGET_PAGE_SIZE. + * If this ever occurs, one should use the ppcemb target instead + * of the ppc or ppc64 one + */ + if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) { + cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u " + "are not supported (%d)\n", + tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7)); + } + tlb->EPN = val & ~(tlb->size - 1); + if (val & PPC4XX_TLBHI_V) { + tlb->prot |= PAGE_VALID; + if (val & PPC4XX_TLBHI_E) { + /* XXX: TO BE FIXED */ + cpu_abort(env, + "Little-endian TLB entries are not supported by now\n"); + } + } else { + tlb->prot &= ~PAGE_VALID; + } + tlb->PID = env->spr[SPR_40x_PID]; /* PID */ + LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx + " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__, + (int)entry, tlb->RPN, tlb->EPN, tlb->size, + tlb->prot & PAGE_READ ? 'r' : '-', + tlb->prot & PAGE_WRITE ? 'w' : '-', + tlb->prot & PAGE_EXEC ? 'x' : '-', + tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); + /* Invalidate new TLB (if valid) */ + if (tlb->prot & PAGE_VALID) { + end = tlb->EPN + tlb->size; + LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end " + TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end); + for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { + tlb_flush_page(env, page); + } + } +} + +void helper_4xx_tlbwe_lo(target_ulong entry, target_ulong val) +{ + ppcemb_tlb_t *tlb; + + LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry, + val); + entry &= PPC4XX_TLB_ENTRY_MASK; + tlb = &env->tlb.tlbe[entry]; + tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK; + tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK; + tlb->prot = PAGE_READ; + if (val & PPC4XX_TLBLO_EX) { + tlb->prot |= PAGE_EXEC; + } + if (val & PPC4XX_TLBLO_WR) { + tlb->prot |= PAGE_WRITE; + } + LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx + " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__, + (int)entry, tlb->RPN, tlb->EPN, tlb->size, + tlb->prot & PAGE_READ ? 'r' : '-', + tlb->prot & PAGE_WRITE ? 'w' : '-', + tlb->prot & PAGE_EXEC ? 'x' : '-', + tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); +} + +target_ulong helper_4xx_tlbsx(target_ulong address) +{ + return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]); +} + +/* PowerPC 440 TLB management */ +void helper_440_tlbwe(uint32_t word, target_ulong entry, target_ulong value) +{ + ppcemb_tlb_t *tlb; + target_ulong EPN, RPN, size; + int do_flush_tlbs; + + LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n", + __func__, word, (int)entry, value); + do_flush_tlbs = 0; + entry &= 0x3F; + tlb = &env->tlb.tlbe[entry]; + switch (word) { + default: + /* Just here to please gcc */ + case 0: + EPN = value & 0xFFFFFC00; + if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) { + do_flush_tlbs = 1; + } + tlb->EPN = EPN; + size = booke_tlb_to_page_size((value >> 4) & 0xF); + if ((tlb->prot & PAGE_VALID) && tlb->size < size) { + do_flush_tlbs = 1; + } + tlb->size = size; + tlb->attr &= ~0x1; + tlb->attr |= (value >> 8) & 1; + if (value & 0x200) { + tlb->prot |= PAGE_VALID; + } else { + if (tlb->prot & PAGE_VALID) { + tlb->prot &= ~PAGE_VALID; + do_flush_tlbs = 1; + } + } + tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF; + if (do_flush_tlbs) { + tlb_flush(env, 1); + } + break; + case 1: + RPN = value & 0xFFFFFC0F; + if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) { + tlb_flush(env, 1); + } + tlb->RPN = RPN; + break; + case 2: + tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00); + tlb->prot = tlb->prot & PAGE_VALID; + if (value & 0x1) { + tlb->prot |= PAGE_READ << 4; + } + if (value & 0x2) { + tlb->prot |= PAGE_WRITE << 4; + } + if (value & 0x4) { + tlb->prot |= PAGE_EXEC << 4; + } + if (value & 0x8) { + tlb->prot |= PAGE_READ; + } + if (value & 0x10) { + tlb->prot |= PAGE_WRITE; + } + if (value & 0x20) { + tlb->prot |= PAGE_EXEC; + } + break; + } +} + +target_ulong helper_440_tlbre(uint32_t word, target_ulong entry) +{ + ppcemb_tlb_t *tlb; + target_ulong ret; + int size; + + entry &= 0x3F; + tlb = &env->tlb.tlbe[entry]; + switch (word) { + default: + /* Just here to please gcc */ + case 0: + ret = tlb->EPN; + size = booke_page_size_to_tlb(tlb->size); + if (size < 0 || size > 0xF) { + size = 1; + } + ret |= size << 4; + if (tlb->attr & 0x1) { + ret |= 0x100; + } + if (tlb->prot & PAGE_VALID) { + ret |= 0x200; + } + env->spr[SPR_440_MMUCR] &= ~0x000000FF; + env->spr[SPR_440_MMUCR] |= tlb->PID; + break; + case 1: + ret = tlb->RPN; + break; + case 2: + ret = tlb->attr & ~0x1; + if (tlb->prot & (PAGE_READ << 4)) { + ret |= 0x1; + } + if (tlb->prot & (PAGE_WRITE << 4)) { + ret |= 0x2; + } + if (tlb->prot & (PAGE_EXEC << 4)) { + ret |= 0x4; + } + if (tlb->prot & PAGE_READ) { + ret |= 0x8; + } + if (tlb->prot & PAGE_WRITE) { + ret |= 0x10; + } + if (tlb->prot & PAGE_EXEC) { + ret |= 0x20; + } + break; + } + return ret; +} + +target_ulong helper_440_tlbsx(target_ulong address) +{ + return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF); +} + +/* PowerPC BookE 2.06 TLB management */ + +static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env) +{ + uint32_t tlbncfg = 0; + int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT; + int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK); + int tlb; + + tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT; + tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb]; + + if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) { + cpu_abort(env, "we don't support HES yet\n"); + } + + return booke206_get_tlbm(env, tlb, ea, esel); +} + +void helper_booke_setpid(uint32_t pidn, target_ulong pid) +{ + env->spr[pidn] = pid; + /* changing PIDs mean we're in a different address space now */ + tlb_flush(env, 1); +} + +void helper_booke206_tlbwe(void) +{ + uint32_t tlbncfg, tlbn; + ppcmas_tlb_t *tlb; + uint32_t size_tlb, size_ps; + + switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) { + case MAS0_WQ_ALWAYS: + /* good to go, write that entry */ + break; + case MAS0_WQ_COND: + /* XXX check if reserved */ + if (0) { + return; + } + break; + case MAS0_WQ_CLR_RSRV: + /* XXX clear entry */ + return; + default: + /* no idea what to do */ + return; + } + + if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) && + !msr_gs) { + /* XXX we don't support direct LRAT setting yet */ + fprintf(stderr, "cpu: don't support LRAT setting yet\n"); + return; + } + + tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT; + tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn]; + + tlb = booke206_cur_tlb(env); + + if (!tlb) { + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL); + } + + /* check that we support the targeted size */ + size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; + size_ps = booke206_tlbnps(env, tlbn); + if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) && + !(size_ps & (1 << size_tlb))) { + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL); + } + + if (msr_gs) { + cpu_abort(env, "missing HV implementation\n"); + } + tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) | + env->spr[SPR_BOOKE_MAS3]; + tlb->mas1 = env->spr[SPR_BOOKE_MAS1]; + + /* MAV 1.0 only */ + if (!(tlbncfg & TLBnCFG_AVAIL)) { + /* force !AVAIL TLB entries to correct page size */ + tlb->mas1 &= ~MAS1_TSIZE_MASK; + /* XXX can be configured in MMUCSR0 */ + tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12; + } + + /* XXX needs to change when supporting 64-bit e500 */ + tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff; + + if (!(tlbncfg & TLBnCFG_IPROT)) { + /* no IPROT supported by TLB */ + tlb->mas1 &= ~MAS1_IPROT; + } + + if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) { + tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK); + } else { + tlb_flush(env, 1); + } +} + +static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb) +{ + int tlbn = booke206_tlbm_to_tlbn(env, tlb); + int way = booke206_tlbm_to_way(env, tlb); + + env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT; + env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT; + env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; + + env->spr[SPR_BOOKE_MAS1] = tlb->mas1; + env->spr[SPR_BOOKE_MAS2] = tlb->mas2; + env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3; + env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32; +} + +void helper_booke206_tlbre(void) +{ + ppcmas_tlb_t *tlb = NULL; + + tlb = booke206_cur_tlb(env); + if (!tlb) { + env->spr[SPR_BOOKE_MAS1] = 0; + } else { + booke206_tlb_to_mas(env, tlb); + } +} + +void helper_booke206_tlbsx(target_ulong address) +{ + ppcmas_tlb_t *tlb = NULL; + int i, j; + target_phys_addr_t raddr; + uint32_t spid, sas; + + spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT; + sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS; + + for (i = 0; i < BOOKE206_MAX_TLBN; i++) { + int ways = booke206_tlb_ways(env, i); + + for (j = 0; j < ways; j++) { + tlb = booke206_get_tlbm(env, i, address, j); + + if (!tlb) { + continue; + } + + if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) { + continue; + } + + if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { + continue; + } + + booke206_tlb_to_mas(env, tlb); + return; + } + } + + /* no entry found, fill with defaults */ + env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK; + env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK; + env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK; + env->spr[SPR_BOOKE_MAS3] = 0; + env->spr[SPR_BOOKE_MAS7] = 0; + + if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) { + env->spr[SPR_BOOKE_MAS1] |= MAS1_TS; + } + + env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16) + << MAS1_TID_SHIFT; + + /* next victim logic */ + env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT; + env->last_way++; + env->last_way &= booke206_tlb_ways(env, 0) - 1; + env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; +} + +static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn, + uint32_t ea) +{ + int i; + int ways = booke206_tlb_ways(env, tlbn); + target_ulong mask; + + for (i = 0; i < ways; i++) { + ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i); + if (!tlb) { + continue; + } + mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); + if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) && + !(tlb->mas1 & MAS1_IPROT)) { + tlb->mas1 &= ~MAS1_VALID; + } + } +} + +void helper_booke206_tlbivax(target_ulong address) +{ + if (address & 0x4) { + /* flush all entries */ + if (address & 0x8) { + /* flush all of TLB1 */ + booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1); + } else { + /* flush all of TLB0 */ + booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0); + } + return; + } + + if (address & 0x8) { + /* flush TLB1 entries */ + booke206_invalidate_ea_tlb(env, 1, address); + tlb_flush(env, 1); + } else { + /* flush TLB0 entries */ + booke206_invalidate_ea_tlb(env, 0, address); + tlb_flush_page(env, address & MAS2_EPN_MASK); + } +} + +void helper_booke206_tlbilx0(target_ulong address) +{ + /* XXX missing LPID handling */ + booke206_flush_tlb(env, -1, 1); +} + +void helper_booke206_tlbilx1(target_ulong address) +{ + int i, j; + int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID); + ppcmas_tlb_t *tlb = env->tlb.tlbm; + int tlb_size; + + /* XXX missing LPID handling */ + for (i = 0; i < BOOKE206_MAX_TLBN; i++) { + tlb_size = booke206_tlb_size(env, i); + for (j = 0; j < tlb_size; j++) { + if (!(tlb[j].mas1 & MAS1_IPROT) && + ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) { + tlb[j].mas1 &= ~MAS1_VALID; + } + } + tlb += booke206_tlb_size(env, i); + } + tlb_flush(env, 1); +} + +void helper_booke206_tlbilx3(target_ulong address) +{ + int i, j; + ppcmas_tlb_t *tlb; + int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID); + int pid = tid >> MAS6_SPID_SHIFT; + int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS; + int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0; + /* XXX check for unsupported isize and raise an invalid opcode then */ + int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK; + /* XXX implement MAV2 handling */ + bool mav2 = false; + + /* XXX missing LPID handling */ + /* flush by pid and ea */ + for (i = 0; i < BOOKE206_MAX_TLBN; i++) { + int ways = booke206_tlb_ways(env, i); + + for (j = 0; j < ways; j++) { + tlb = booke206_get_tlbm(env, i, address, j); + if (!tlb) { + continue; + } + if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) || + (tlb->mas1 & MAS1_IPROT) || + ((tlb->mas1 & MAS1_IND) != ind) || + ((tlb->mas8 & MAS8_TGS) != sgs)) { + continue; + } + if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) { + /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */ + continue; + } + /* XXX e500mc doesn't match SAS, but other cores might */ + tlb->mas1 &= ~MAS1_VALID; + } + } + tlb_flush(env, 1); +} + +void helper_booke206_tlbflush(uint32_t type) +{ + int flags = 0; + + if (type & 2) { + flags |= BOOKE206_FLUSH_TLB1; + } + + if (type & 4) { + flags |= BOOKE206_FLUSH_TLB0; + } + + booke206_flush_tlb(env, flags, 1); +} +#endif diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 55b9e9dcb9..c854c71225 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -29,13 +29,6 @@ #endif /* !defined(CONFIG_USER_ONLY) */ //#define DEBUG_OP -//#define DEBUG_SOFTWARE_TLB - -#ifdef DEBUG_SOFTWARE_TLB -# define LOG_SWTLB(...) qemu_log(__VA_ARGS__) -#else -# define LOG_SWTLB(...) do { } while (0) -#endif /*****************************************************************************/ /* SPR accesses */ @@ -196,36 +189,6 @@ void helper_store_booke_tsr(target_ulong val) { store_booke_tsr(env, val); } - -void helper_store_ibatu(uint32_t nr, target_ulong val) -{ - ppc_store_ibatu(env, nr, val); -} - -void helper_store_ibatl(uint32_t nr, target_ulong val) -{ - ppc_store_ibatl(env, nr, val); -} - -void helper_store_dbatu(uint32_t nr, target_ulong val) -{ - ppc_store_dbatu(env, nr, val); -} - -void helper_store_dbatl(uint32_t nr, target_ulong val) -{ - ppc_store_dbatl(env, nr, val); -} - -void helper_store_601_batl(uint32_t nr, target_ulong val) -{ - ppc_store_ibatl_601(env, nr, val); -} - -void helper_store_601_batu(uint32_t nr, target_ulong val) -{ - ppc_store_ibatu_601(env, nr, val); -} #endif /*****************************************************************************/ @@ -417,27 +380,6 @@ target_ulong helper_clcs(uint32_t arg) } } -#if !defined(CONFIG_USER_ONLY) -target_ulong helper_rac(target_ulong addr) -{ - mmu_ctx_t ctx; - int nb_BATs; - target_ulong ret = 0; - - /* We don't have to generate many instances of this instruction, - * as rac is supervisor only. - */ - /* XXX: FIX THIS: Pretend we have no BAT */ - nb_BATs = env->nb_BATs; - env->nb_BATs = 0; - if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) { - ret = ctx.raddr; - } - env->nb_BATs = nb_BATs; - return ret; -} -#endif - /*****************************************************************************/ /* Embedded PowerPC specific helpers */ @@ -578,800 +520,4 @@ void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx, } env = saved_env; } - -/* Segment registers load and store */ -target_ulong helper_load_sr(target_ulong sr_num) -{ -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { - return ppc_load_sr(env, sr_num); - } -#endif - return env->sr[sr_num]; -} - -void helper_store_sr(target_ulong sr_num, target_ulong val) -{ - ppc_store_sr(env, sr_num, val); -} - -/* SLB management */ -#if defined(TARGET_PPC64) -void helper_store_slb(target_ulong rb, target_ulong rs) -{ - if (ppc_store_slb(env, rb, rs) < 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL); - } -} - -target_ulong helper_load_slb_esid(target_ulong rb) -{ - target_ulong rt; - - if (ppc_load_slb_esid(env, rb, &rt) < 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL); - } - return rt; -} - -target_ulong helper_load_slb_vsid(target_ulong rb) -{ - target_ulong rt; - - if (ppc_load_slb_vsid(env, rb, &rt) < 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL); - } - return rt; -} - -void helper_slbia(void) -{ - ppc_slb_invalidate_all(env); -} - -void helper_slbie(target_ulong addr) -{ - ppc_slb_invalidate_one(env, addr); -} - -#endif /* defined(TARGET_PPC64) */ - -/* TLB management */ -void helper_tlbia(void) -{ - ppc_tlb_invalidate_all(env); -} - -void helper_tlbie(target_ulong addr) -{ - ppc_tlb_invalidate_one(env, addr); -} - -/* Software driven TLBs management */ -/* PowerPC 602/603 software TLB load instructions helpers */ -static void do_6xx_tlb(target_ulong new_EPN, int is_code) -{ - target_ulong RPN, CMP, EPN; - int way; - - RPN = env->spr[SPR_RPA]; - if (is_code) { - CMP = env->spr[SPR_ICMP]; - EPN = env->spr[SPR_IMISS]; - } else { - CMP = env->spr[SPR_DCMP]; - EPN = env->spr[SPR_DMISS]; - } - way = (env->spr[SPR_SRR1] >> 17) & 1; - (void)EPN; /* avoid a compiler warning */ - LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx - " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP, - RPN, way); - /* Store this TLB */ - ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK), - way, is_code, CMP, RPN); -} - -void helper_6xx_tlbd(target_ulong EPN) -{ - do_6xx_tlb(EPN, 0); -} - -void helper_6xx_tlbi(target_ulong EPN) -{ - do_6xx_tlb(EPN, 1); -} - -/* PowerPC 74xx software TLB load instructions helpers */ -static void do_74xx_tlb(target_ulong new_EPN, int is_code) -{ - target_ulong RPN, CMP, EPN; - int way; - - RPN = env->spr[SPR_PTELO]; - CMP = env->spr[SPR_PTEHI]; - EPN = env->spr[SPR_TLBMISS] & ~0x3; - way = env->spr[SPR_TLBMISS] & 0x3; - (void)EPN; /* avoid a compiler warning */ - LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx - " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP, - RPN, way); - /* Store this TLB */ - ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK), - way, is_code, CMP, RPN); -} - -void helper_74xx_tlbd(target_ulong EPN) -{ - do_74xx_tlb(EPN, 0); -} - -void helper_74xx_tlbi(target_ulong EPN) -{ - do_74xx_tlb(EPN, 1); -} - -static inline target_ulong booke_tlb_to_page_size(int size) -{ - return 1024 << (2 * size); -} - -static inline int booke_page_size_to_tlb(target_ulong page_size) -{ - int size; - - switch (page_size) { - case 0x00000400UL: - size = 0x0; - break; - case 0x00001000UL: - size = 0x1; - break; - case 0x00004000UL: - size = 0x2; - break; - case 0x00010000UL: - size = 0x3; - break; - case 0x00040000UL: - size = 0x4; - break; - case 0x00100000UL: - size = 0x5; - break; - case 0x00400000UL: - size = 0x6; - break; - case 0x01000000UL: - size = 0x7; - break; - case 0x04000000UL: - size = 0x8; - break; - case 0x10000000UL: - size = 0x9; - break; - case 0x40000000UL: - size = 0xA; - break; -#if defined(TARGET_PPC64) - case 0x000100000000ULL: - size = 0xB; - break; - case 0x000400000000ULL: - size = 0xC; - break; - case 0x001000000000ULL: - size = 0xD; - break; - case 0x004000000000ULL: - size = 0xE; - break; - case 0x010000000000ULL: - size = 0xF; - break; -#endif - default: - size = -1; - break; - } - - return size; -} - -/* Helpers for 4xx TLB management */ -#define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */ - -#define PPC4XX_TLBHI_V 0x00000040 -#define PPC4XX_TLBHI_E 0x00000020 -#define PPC4XX_TLBHI_SIZE_MIN 0 -#define PPC4XX_TLBHI_SIZE_MAX 7 -#define PPC4XX_TLBHI_SIZE_DEFAULT 1 -#define PPC4XX_TLBHI_SIZE_SHIFT 7 -#define PPC4XX_TLBHI_SIZE_MASK 0x00000007 - -#define PPC4XX_TLBLO_EX 0x00000200 -#define PPC4XX_TLBLO_WR 0x00000100 -#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF -#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00 - -target_ulong helper_4xx_tlbre_hi(target_ulong entry) -{ - ppcemb_tlb_t *tlb; - target_ulong ret; - int size; - - entry &= PPC4XX_TLB_ENTRY_MASK; - tlb = &env->tlb.tlbe[entry]; - ret = tlb->EPN; - if (tlb->prot & PAGE_VALID) { - ret |= PPC4XX_TLBHI_V; - } - size = booke_page_size_to_tlb(tlb->size); - if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) { - size = PPC4XX_TLBHI_SIZE_DEFAULT; - } - ret |= size << PPC4XX_TLBHI_SIZE_SHIFT; - env->spr[SPR_40x_PID] = tlb->PID; - return ret; -} - -target_ulong helper_4xx_tlbre_lo(target_ulong entry) -{ - ppcemb_tlb_t *tlb; - target_ulong ret; - - entry &= PPC4XX_TLB_ENTRY_MASK; - tlb = &env->tlb.tlbe[entry]; - ret = tlb->RPN; - if (tlb->prot & PAGE_EXEC) { - ret |= PPC4XX_TLBLO_EX; - } - if (tlb->prot & PAGE_WRITE) { - ret |= PPC4XX_TLBLO_WR; - } - return ret; -} - -void helper_4xx_tlbwe_hi(target_ulong entry, target_ulong val) -{ - ppcemb_tlb_t *tlb; - target_ulong page, end; - - LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry, - val); - entry &= PPC4XX_TLB_ENTRY_MASK; - tlb = &env->tlb.tlbe[entry]; - /* Invalidate previous TLB (if it's valid) */ - if (tlb->prot & PAGE_VALID) { - end = tlb->EPN + tlb->size; - LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end " - TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end); - for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { - tlb_flush_page(env, page); - } - } - tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT) - & PPC4XX_TLBHI_SIZE_MASK); - /* We cannot handle TLB size < TARGET_PAGE_SIZE. - * If this ever occurs, one should use the ppcemb target instead - * of the ppc or ppc64 one - */ - if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) { - cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u " - "are not supported (%d)\n", - tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7)); - } - tlb->EPN = val & ~(tlb->size - 1); - if (val & PPC4XX_TLBHI_V) { - tlb->prot |= PAGE_VALID; - if (val & PPC4XX_TLBHI_E) { - /* XXX: TO BE FIXED */ - cpu_abort(env, - "Little-endian TLB entries are not supported by now\n"); - } - } else { - tlb->prot &= ~PAGE_VALID; - } - tlb->PID = env->spr[SPR_40x_PID]; /* PID */ - LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx - " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__, - (int)entry, tlb->RPN, tlb->EPN, tlb->size, - tlb->prot & PAGE_READ ? 'r' : '-', - tlb->prot & PAGE_WRITE ? 'w' : '-', - tlb->prot & PAGE_EXEC ? 'x' : '-', - tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); - /* Invalidate new TLB (if valid) */ - if (tlb->prot & PAGE_VALID) { - end = tlb->EPN + tlb->size; - LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end " - TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end); - for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { - tlb_flush_page(env, page); - } - } -} - -void helper_4xx_tlbwe_lo(target_ulong entry, target_ulong val) -{ - ppcemb_tlb_t *tlb; - - LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry, - val); - entry &= PPC4XX_TLB_ENTRY_MASK; - tlb = &env->tlb.tlbe[entry]; - tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK; - tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK; - tlb->prot = PAGE_READ; - if (val & PPC4XX_TLBLO_EX) { - tlb->prot |= PAGE_EXEC; - } - if (val & PPC4XX_TLBLO_WR) { - tlb->prot |= PAGE_WRITE; - } - LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx - " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__, - (int)entry, tlb->RPN, tlb->EPN, tlb->size, - tlb->prot & PAGE_READ ? 'r' : '-', - tlb->prot & PAGE_WRITE ? 'w' : '-', - tlb->prot & PAGE_EXEC ? 'x' : '-', - tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); -} - -target_ulong helper_4xx_tlbsx(target_ulong address) -{ - return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]); -} - -/* PowerPC 440 TLB management */ -void helper_440_tlbwe(uint32_t word, target_ulong entry, target_ulong value) -{ - ppcemb_tlb_t *tlb; - target_ulong EPN, RPN, size; - int do_flush_tlbs; - - LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n", - __func__, word, (int)entry, value); - do_flush_tlbs = 0; - entry &= 0x3F; - tlb = &env->tlb.tlbe[entry]; - switch (word) { - default: - /* Just here to please gcc */ - case 0: - EPN = value & 0xFFFFFC00; - if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) { - do_flush_tlbs = 1; - } - tlb->EPN = EPN; - size = booke_tlb_to_page_size((value >> 4) & 0xF); - if ((tlb->prot & PAGE_VALID) && tlb->size < size) { - do_flush_tlbs = 1; - } - tlb->size = size; - tlb->attr &= ~0x1; - tlb->attr |= (value >> 8) & 1; - if (value & 0x200) { - tlb->prot |= PAGE_VALID; - } else { - if (tlb->prot & PAGE_VALID) { - tlb->prot &= ~PAGE_VALID; - do_flush_tlbs = 1; - } - } - tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF; - if (do_flush_tlbs) { - tlb_flush(env, 1); - } - break; - case 1: - RPN = value & 0xFFFFFC0F; - if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) { - tlb_flush(env, 1); - } - tlb->RPN = RPN; - break; - case 2: - tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00); - tlb->prot = tlb->prot & PAGE_VALID; - if (value & 0x1) { - tlb->prot |= PAGE_READ << 4; - } - if (value & 0x2) { - tlb->prot |= PAGE_WRITE << 4; - } - if (value & 0x4) { - tlb->prot |= PAGE_EXEC << 4; - } - if (value & 0x8) { - tlb->prot |= PAGE_READ; - } - if (value & 0x10) { - tlb->prot |= PAGE_WRITE; - } - if (value & 0x20) { - tlb->prot |= PAGE_EXEC; - } - break; - } -} - -target_ulong helper_440_tlbre(uint32_t word, target_ulong entry) -{ - ppcemb_tlb_t *tlb; - target_ulong ret; - int size; - - entry &= 0x3F; - tlb = &env->tlb.tlbe[entry]; - switch (word) { - default: - /* Just here to please gcc */ - case 0: - ret = tlb->EPN; - size = booke_page_size_to_tlb(tlb->size); - if (size < 0 || size > 0xF) { - size = 1; - } - ret |= size << 4; - if (tlb->attr & 0x1) { - ret |= 0x100; - } - if (tlb->prot & PAGE_VALID) { - ret |= 0x200; - } - env->spr[SPR_440_MMUCR] &= ~0x000000FF; - env->spr[SPR_440_MMUCR] |= tlb->PID; - break; - case 1: - ret = tlb->RPN; - break; - case 2: - ret = tlb->attr & ~0x1; - if (tlb->prot & (PAGE_READ << 4)) { - ret |= 0x1; - } - if (tlb->prot & (PAGE_WRITE << 4)) { - ret |= 0x2; - } - if (tlb->prot & (PAGE_EXEC << 4)) { - ret |= 0x4; - } - if (tlb->prot & PAGE_READ) { - ret |= 0x8; - } - if (tlb->prot & PAGE_WRITE) { - ret |= 0x10; - } - if (tlb->prot & PAGE_EXEC) { - ret |= 0x20; - } - break; - } - return ret; -} - -target_ulong helper_440_tlbsx(target_ulong address) -{ - return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF); -} - -/* PowerPC BookE 2.06 TLB management */ - -static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env) -{ - uint32_t tlbncfg = 0; - int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT; - int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK); - int tlb; - - tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT; - tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb]; - - if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) { - cpu_abort(env, "we don't support HES yet\n"); - } - - return booke206_get_tlbm(env, tlb, ea, esel); -} - -void helper_booke_setpid(uint32_t pidn, target_ulong pid) -{ - env->spr[pidn] = pid; - /* changing PIDs mean we're in a different address space now */ - tlb_flush(env, 1); -} - -void helper_booke206_tlbwe(void) -{ - uint32_t tlbncfg, tlbn; - ppcmas_tlb_t *tlb; - uint32_t size_tlb, size_ps; - - switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) { - case MAS0_WQ_ALWAYS: - /* good to go, write that entry */ - break; - case MAS0_WQ_COND: - /* XXX check if reserved */ - if (0) { - return; - } - break; - case MAS0_WQ_CLR_RSRV: - /* XXX clear entry */ - return; - default: - /* no idea what to do */ - return; - } - - if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) && - !msr_gs) { - /* XXX we don't support direct LRAT setting yet */ - fprintf(stderr, "cpu: don't support LRAT setting yet\n"); - return; - } - - tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT; - tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn]; - - tlb = booke206_cur_tlb(env); - - if (!tlb) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | - POWERPC_EXCP_INVAL_INVAL); - } - - /* check that we support the targeted size */ - size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; - size_ps = booke206_tlbnps(env, tlbn); - if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) && - !(size_ps & (1 << size_tlb))) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | - POWERPC_EXCP_INVAL_INVAL); - } - - if (msr_gs) { - cpu_abort(env, "missing HV implementation\n"); - } - tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) | - env->spr[SPR_BOOKE_MAS3]; - tlb->mas1 = env->spr[SPR_BOOKE_MAS1]; - - /* MAV 1.0 only */ - if (!(tlbncfg & TLBnCFG_AVAIL)) { - /* force !AVAIL TLB entries to correct page size */ - tlb->mas1 &= ~MAS1_TSIZE_MASK; - /* XXX can be configured in MMUCSR0 */ - tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12; - } - - /* XXX needs to change when supporting 64-bit e500 */ - tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff; - - if (!(tlbncfg & TLBnCFG_IPROT)) { - /* no IPROT supported by TLB */ - tlb->mas1 &= ~MAS1_IPROT; - } - - if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) { - tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK); - } else { - tlb_flush(env, 1); - } -} - -static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb) -{ - int tlbn = booke206_tlbm_to_tlbn(env, tlb); - int way = booke206_tlbm_to_way(env, tlb); - - env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT; - env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT; - env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; - - env->spr[SPR_BOOKE_MAS1] = tlb->mas1; - env->spr[SPR_BOOKE_MAS2] = tlb->mas2; - env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3; - env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32; -} - -void helper_booke206_tlbre(void) -{ - ppcmas_tlb_t *tlb = NULL; - - tlb = booke206_cur_tlb(env); - if (!tlb) { - env->spr[SPR_BOOKE_MAS1] = 0; - } else { - booke206_tlb_to_mas(env, tlb); - } -} - -void helper_booke206_tlbsx(target_ulong address) -{ - ppcmas_tlb_t *tlb = NULL; - int i, j; - target_phys_addr_t raddr; - uint32_t spid, sas; - - spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT; - sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS; - - for (i = 0; i < BOOKE206_MAX_TLBN; i++) { - int ways = booke206_tlb_ways(env, i); - - for (j = 0; j < ways; j++) { - tlb = booke206_get_tlbm(env, i, address, j); - - if (!tlb) { - continue; - } - - if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) { - continue; - } - - if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { - continue; - } - - booke206_tlb_to_mas(env, tlb); - return; - } - } - - /* no entry found, fill with defaults */ - env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK; - env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK; - env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK; - env->spr[SPR_BOOKE_MAS3] = 0; - env->spr[SPR_BOOKE_MAS7] = 0; - - if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) { - env->spr[SPR_BOOKE_MAS1] |= MAS1_TS; - } - - env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16) - << MAS1_TID_SHIFT; - - /* next victim logic */ - env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT; - env->last_way++; - env->last_way &= booke206_tlb_ways(env, 0) - 1; - env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; -} - -static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn, - uint32_t ea) -{ - int i; - int ways = booke206_tlb_ways(env, tlbn); - target_ulong mask; - - for (i = 0; i < ways; i++) { - ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i); - if (!tlb) { - continue; - } - mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); - if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) && - !(tlb->mas1 & MAS1_IPROT)) { - tlb->mas1 &= ~MAS1_VALID; - } - } -} - -void helper_booke206_tlbivax(target_ulong address) -{ - if (address & 0x4) { - /* flush all entries */ - if (address & 0x8) { - /* flush all of TLB1 */ - booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1); - } else { - /* flush all of TLB0 */ - booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0); - } - return; - } - - if (address & 0x8) { - /* flush TLB1 entries */ - booke206_invalidate_ea_tlb(env, 1, address); - tlb_flush(env, 1); - } else { - /* flush TLB0 entries */ - booke206_invalidate_ea_tlb(env, 0, address); - tlb_flush_page(env, address & MAS2_EPN_MASK); - } -} - -void helper_booke206_tlbilx0(target_ulong address) -{ - /* XXX missing LPID handling */ - booke206_flush_tlb(env, -1, 1); -} - -void helper_booke206_tlbilx1(target_ulong address) -{ - int i, j; - int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID); - ppcmas_tlb_t *tlb = env->tlb.tlbm; - int tlb_size; - - /* XXX missing LPID handling */ - for (i = 0; i < BOOKE206_MAX_TLBN; i++) { - tlb_size = booke206_tlb_size(env, i); - for (j = 0; j < tlb_size; j++) { - if (!(tlb[j].mas1 & MAS1_IPROT) && - ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) { - tlb[j].mas1 &= ~MAS1_VALID; - } - } - tlb += booke206_tlb_size(env, i); - } - tlb_flush(env, 1); -} - -void helper_booke206_tlbilx3(target_ulong address) -{ - int i, j; - ppcmas_tlb_t *tlb; - int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID); - int pid = tid >> MAS6_SPID_SHIFT; - int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS; - int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0; - /* XXX check for unsupported isize and raise an invalid opcode then */ - int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK; - /* XXX implement MAV2 handling */ - bool mav2 = false; - - /* XXX missing LPID handling */ - /* flush by pid and ea */ - for (i = 0; i < BOOKE206_MAX_TLBN; i++) { - int ways = booke206_tlb_ways(env, i); - - for (j = 0; j < ways; j++) { - tlb = booke206_get_tlbm(env, i, address, j); - if (!tlb) { - continue; - } - if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) || - (tlb->mas1 & MAS1_IPROT) || - ((tlb->mas1 & MAS1_IND) != ind) || - ((tlb->mas8 & MAS8_TGS) != sgs)) { - continue; - } - if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) { - /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */ - continue; - } - /* XXX e500mc doesn't match SAS, but other cores might */ - tlb->mas1 &= ~MAS1_VALID; - } - } - tlb_flush(env, 1); -} - -void helper_booke206_tlbflush(uint32_t type) -{ - int flags = 0; - - if (type & 2) { - flags |= BOOKE206_FLUSH_TLB1; - } - - if (type & 4) { - flags |= BOOKE206_FLUSH_TLB0; - } - - booke206_flush_tlb(env, flags, 1); -} #endif /* !CONFIG_USER_ONLY */ From c6c7cf05e126d4dd1d9bfcb1aaf1b2cc66f5fa9a Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:31 +0000 Subject: [PATCH 11/72] ppc: Avoid AREG0 for MMU etc. helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an explicit CPUPPCState parameter instead of relying on AREG0. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 1 - target-ppc/helper.h | 74 +++++++++++++++--------------- target-ppc/mmu_helper.c | 91 +++++++++++++++++++------------------ target-ppc/translate.c | 85 ++++++++++++++++++---------------- target-ppc/translate_init.c | 24 +++++----- 5 files changed, 142 insertions(+), 133 deletions(-) diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 0f89c2c53a..71e25b14e1 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -7,5 +7,4 @@ obj-y += fpu_helper.o obj-y += int_helper.o obj-y += mmu_helper.o -$(obj)/mmu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 7074bad859..b1f7ba5bcb 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -324,38 +324,38 @@ DEF_HELPER_3(efdcmpgt, i32, env, i64, i64) DEF_HELPER_3(efdcmpeq, i32, env, i64, i64) #if !defined(CONFIG_USER_ONLY) -DEF_HELPER_1(4xx_tlbre_hi, tl, tl) -DEF_HELPER_1(4xx_tlbre_lo, tl, tl) -DEF_HELPER_2(4xx_tlbwe_hi, void, tl, tl) -DEF_HELPER_2(4xx_tlbwe_lo, void, tl, tl) -DEF_HELPER_1(4xx_tlbsx, tl, tl) -DEF_HELPER_2(440_tlbre, tl, i32, tl) -DEF_HELPER_3(440_tlbwe, void, i32, tl, tl) -DEF_HELPER_1(440_tlbsx, tl, tl) -DEF_HELPER_0(booke206_tlbre, void) -DEF_HELPER_0(booke206_tlbwe, void) -DEF_HELPER_1(booke206_tlbsx, void, tl) -DEF_HELPER_1(booke206_tlbivax, void, tl) -DEF_HELPER_1(booke206_tlbilx0, void, tl) -DEF_HELPER_1(booke206_tlbilx1, void, tl) -DEF_HELPER_1(booke206_tlbilx3, void, tl) -DEF_HELPER_1(booke206_tlbflush, void, i32) -DEF_HELPER_2(booke_setpid, void, i32, tl) -DEF_HELPER_1(6xx_tlbd, void, tl) -DEF_HELPER_1(6xx_tlbi, void, tl) -DEF_HELPER_1(74xx_tlbd, void, tl) -DEF_HELPER_1(74xx_tlbi, void, tl) -DEF_HELPER_FLAGS_0(tlbia, TCG_CALL_CONST, void) -DEF_HELPER_FLAGS_1(tlbie, TCG_CALL_CONST, void, tl) +DEF_HELPER_2(4xx_tlbre_hi, tl, env, tl) +DEF_HELPER_2(4xx_tlbre_lo, tl, env, tl) +DEF_HELPER_3(4xx_tlbwe_hi, void, env, tl, tl) +DEF_HELPER_3(4xx_tlbwe_lo, void, env, tl, tl) +DEF_HELPER_2(4xx_tlbsx, tl, env, tl) +DEF_HELPER_3(440_tlbre, tl, env, i32, tl) +DEF_HELPER_4(440_tlbwe, void, env, i32, tl, tl) +DEF_HELPER_2(440_tlbsx, tl, env, tl) +DEF_HELPER_1(booke206_tlbre, void, env) +DEF_HELPER_1(booke206_tlbwe, void, env) +DEF_HELPER_2(booke206_tlbsx, void, env, tl) +DEF_HELPER_2(booke206_tlbivax, void, env, tl) +DEF_HELPER_2(booke206_tlbilx0, void, env, tl) +DEF_HELPER_2(booke206_tlbilx1, void, env, tl) +DEF_HELPER_2(booke206_tlbilx3, void, env, tl) +DEF_HELPER_2(booke206_tlbflush, void, env, i32) +DEF_HELPER_3(booke_setpid, void, env, i32, tl) +DEF_HELPER_2(6xx_tlbd, void, env, tl) +DEF_HELPER_2(6xx_tlbi, void, env, tl) +DEF_HELPER_2(74xx_tlbd, void, env, tl) +DEF_HELPER_2(74xx_tlbi, void, env, tl) +DEF_HELPER_FLAGS_1(tlbia, TCG_CALL_CONST, void, env) +DEF_HELPER_FLAGS_2(tlbie, TCG_CALL_CONST, void, env, tl) #if defined(TARGET_PPC64) -DEF_HELPER_FLAGS_2(store_slb, TCG_CALL_CONST, void, tl, tl) -DEF_HELPER_1(load_slb_esid, tl, tl) -DEF_HELPER_1(load_slb_vsid, tl, tl) -DEF_HELPER_FLAGS_0(slbia, TCG_CALL_CONST, void) -DEF_HELPER_FLAGS_1(slbie, TCG_CALL_CONST, void, tl) +DEF_HELPER_FLAGS_3(store_slb, TCG_CALL_CONST, void, env, tl, tl) +DEF_HELPER_2(load_slb_esid, tl, env, tl) +DEF_HELPER_2(load_slb_vsid, tl, env, tl) +DEF_HELPER_FLAGS_1(slbia, TCG_CALL_CONST, void, env) +DEF_HELPER_FLAGS_2(slbie, TCG_CALL_CONST, void, env, tl) #endif -DEF_HELPER_FLAGS_1(load_sr, TCG_CALL_CONST, tl, tl); -DEF_HELPER_FLAGS_2(store_sr, TCG_CALL_CONST, void, tl, tl) +DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_CONST, tl, env, tl); +DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_CONST, void, env, tl, tl) DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) DEF_HELPER_1(msgsnd, void, tl) @@ -365,7 +365,7 @@ DEF_HELPER_2(msgclr, void, env, tl) DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32) DEF_HELPER_FLAGS_1(clcs, TCG_CALL_CONST | TCG_CALL_PURE, tl, i32) #if !defined(CONFIG_USER_ONLY) -DEF_HELPER_1(rac, tl, tl) +DEF_HELPER_2(rac, tl, env, tl) #endif DEF_HELPER_3(div, tl, env, tl, tl) DEF_HELPER_3(divo, tl, env, tl, tl) @@ -405,12 +405,12 @@ DEF_HELPER_1(store_40x_dbcr0, void, tl) DEF_HELPER_1(store_40x_sler, void, tl) DEF_HELPER_1(store_booke_tcr, void, tl) DEF_HELPER_1(store_booke_tsr, void, tl) -DEF_HELPER_2(store_ibatl, void, i32, tl) -DEF_HELPER_2(store_ibatu, void, i32, tl) -DEF_HELPER_2(store_dbatl, void, i32, tl) -DEF_HELPER_2(store_dbatu, void, i32, tl) -DEF_HELPER_2(store_601_batl, void, i32, tl) -DEF_HELPER_2(store_601_batu, void, i32, tl) +DEF_HELPER_3(store_ibatl, void, env, i32, tl) +DEF_HELPER_3(store_ibatu, void, env, i32, tl) +DEF_HELPER_3(store_dbatl, void, env, i32, tl) +DEF_HELPER_3(store_dbatu, void, env, i32, tl) +DEF_HELPER_3(store_601_batl, void, env, i32, tl) +DEF_HELPER_3(store_601_batu, void, env, i32, tl) #endif #include "def-helper.h" diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 81800b618f..7bd6230d08 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -17,7 +17,6 @@ * License along with this library; if not, see . */ #include "cpu.h" -#include "dyngen-exec.h" #include "helper.h" //#define DEBUG_SOFTWARE_TLB @@ -32,38 +31,38 @@ /* SPR accesses */ #if !defined(CONFIG_USER_ONLY) -void helper_store_ibatu(uint32_t nr, target_ulong val) +void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong val) { ppc_store_ibatu(env, nr, val); } -void helper_store_ibatl(uint32_t nr, target_ulong val) +void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong val) { ppc_store_ibatl(env, nr, val); } -void helper_store_dbatu(uint32_t nr, target_ulong val) +void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong val) { ppc_store_dbatu(env, nr, val); } -void helper_store_dbatl(uint32_t nr, target_ulong val) +void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong val) { ppc_store_dbatl(env, nr, val); } -void helper_store_601_batl(uint32_t nr, target_ulong val) +void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong val) { ppc_store_ibatl_601(env, nr, val); } -void helper_store_601_batu(uint32_t nr, target_ulong val) +void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong val) { ppc_store_ibatu_601(env, nr, val); } /* Segment registers load and store */ -target_ulong helper_load_sr(target_ulong sr_num) +target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num) { #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { @@ -73,14 +72,14 @@ target_ulong helper_load_sr(target_ulong sr_num) return env->sr[sr_num]; } -void helper_store_sr(target_ulong sr_num, target_ulong val) +void helper_store_sr(CPUPPCState *env, target_ulong sr_num, target_ulong val) { ppc_store_sr(env, sr_num, val); } /* SLB management */ #if defined(TARGET_PPC64) -void helper_store_slb(target_ulong rb, target_ulong rs) +void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) { if (ppc_store_slb(env, rb, rs) < 0) { helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, @@ -88,7 +87,7 @@ void helper_store_slb(target_ulong rb, target_ulong rs) } } -target_ulong helper_load_slb_esid(target_ulong rb) +target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb) { target_ulong rt; @@ -99,7 +98,7 @@ target_ulong helper_load_slb_esid(target_ulong rb) return rt; } -target_ulong helper_load_slb_vsid(target_ulong rb) +target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb) { target_ulong rt; @@ -110,12 +109,12 @@ target_ulong helper_load_slb_vsid(target_ulong rb) return rt; } -void helper_slbia(void) +void helper_slbia(CPUPPCState *env) { ppc_slb_invalidate_all(env); } -void helper_slbie(target_ulong addr) +void helper_slbie(CPUPPCState *env, target_ulong addr) { ppc_slb_invalidate_one(env, addr); } @@ -123,19 +122,19 @@ void helper_slbie(target_ulong addr) #endif /* defined(TARGET_PPC64) */ /* TLB management */ -void helper_tlbia(void) +void helper_tlbia(CPUPPCState *env) { ppc_tlb_invalidate_all(env); } -void helper_tlbie(target_ulong addr) +void helper_tlbie(CPUPPCState *env, target_ulong addr) { ppc_tlb_invalidate_one(env, addr); } /* Software driven TLBs management */ /* PowerPC 602/603 software TLB load instructions helpers */ -static void do_6xx_tlb(target_ulong new_EPN, int is_code) +static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code) { target_ulong RPN, CMP, EPN; int way; @@ -158,18 +157,18 @@ static void do_6xx_tlb(target_ulong new_EPN, int is_code) way, is_code, CMP, RPN); } -void helper_6xx_tlbd(target_ulong EPN) +void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN) { - do_6xx_tlb(EPN, 0); + do_6xx_tlb(env, EPN, 0); } -void helper_6xx_tlbi(target_ulong EPN) +void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN) { - do_6xx_tlb(EPN, 1); + do_6xx_tlb(env, EPN, 1); } /* PowerPC 74xx software TLB load instructions helpers */ -static void do_74xx_tlb(target_ulong new_EPN, int is_code) +static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code) { target_ulong RPN, CMP, EPN; int way; @@ -187,20 +186,20 @@ static void do_74xx_tlb(target_ulong new_EPN, int is_code) way, is_code, CMP, RPN); } -void helper_74xx_tlbd(target_ulong EPN) +void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN) { - do_74xx_tlb(EPN, 0); + do_74xx_tlb(env, EPN, 0); } -void helper_74xx_tlbi(target_ulong EPN) +void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN) { - do_74xx_tlb(EPN, 1); + do_74xx_tlb(env, EPN, 1); } /*****************************************************************************/ /* PowerPC 601 specific instructions (POWER bridge) */ -target_ulong helper_rac(target_ulong addr) +target_ulong helper_rac(CPUPPCState *env, target_ulong addr) { mmu_ctx_t ctx; int nb_BATs; @@ -303,7 +302,7 @@ static inline int booke_page_size_to_tlb(target_ulong page_size) #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00 -target_ulong helper_4xx_tlbre_hi(target_ulong entry) +target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry) { ppcemb_tlb_t *tlb; target_ulong ret; @@ -324,7 +323,7 @@ target_ulong helper_4xx_tlbre_hi(target_ulong entry) return ret; } -target_ulong helper_4xx_tlbre_lo(target_ulong entry) +target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry) { ppcemb_tlb_t *tlb; target_ulong ret; @@ -341,7 +340,8 @@ target_ulong helper_4xx_tlbre_lo(target_ulong entry) return ret; } -void helper_4xx_tlbwe_hi(target_ulong entry, target_ulong val) +void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry, + target_ulong val) { ppcemb_tlb_t *tlb; target_ulong page, end; @@ -400,7 +400,8 @@ void helper_4xx_tlbwe_hi(target_ulong entry, target_ulong val) } } -void helper_4xx_tlbwe_lo(target_ulong entry, target_ulong val) +void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry, + target_ulong val) { ppcemb_tlb_t *tlb; @@ -426,13 +427,14 @@ void helper_4xx_tlbwe_lo(target_ulong entry, target_ulong val) tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); } -target_ulong helper_4xx_tlbsx(target_ulong address) +target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address) { return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]); } /* PowerPC 440 TLB management */ -void helper_440_tlbwe(uint32_t word, target_ulong entry, target_ulong value) +void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry, + target_ulong value) { ppcemb_tlb_t *tlb; target_ulong EPN, RPN, size; @@ -504,7 +506,8 @@ void helper_440_tlbwe(uint32_t word, target_ulong entry, target_ulong value) } } -target_ulong helper_440_tlbre(uint32_t word, target_ulong entry) +target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word, + target_ulong entry) { ppcemb_tlb_t *tlb; target_ulong ret; @@ -559,7 +562,7 @@ target_ulong helper_440_tlbre(uint32_t word, target_ulong entry) return ret; } -target_ulong helper_440_tlbsx(target_ulong address) +target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address) { return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF); } @@ -583,14 +586,14 @@ static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env) return booke206_get_tlbm(env, tlb, ea, esel); } -void helper_booke_setpid(uint32_t pidn, target_ulong pid) +void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid) { env->spr[pidn] = pid; /* changing PIDs mean we're in a different address space now */ tlb_flush(env, 1); } -void helper_booke206_tlbwe(void) +void helper_booke206_tlbwe(CPUPPCState *env) { uint32_t tlbncfg, tlbn; ppcmas_tlb_t *tlb; @@ -687,7 +690,7 @@ static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb) env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32; } -void helper_booke206_tlbre(void) +void helper_booke206_tlbre(CPUPPCState *env) { ppcmas_tlb_t *tlb = NULL; @@ -699,7 +702,7 @@ void helper_booke206_tlbre(void) } } -void helper_booke206_tlbsx(target_ulong address) +void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address) { ppcmas_tlb_t *tlb = NULL; int i, j; @@ -773,7 +776,7 @@ static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn, } } -void helper_booke206_tlbivax(target_ulong address) +void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address) { if (address & 0x4) { /* flush all entries */ @@ -798,13 +801,13 @@ void helper_booke206_tlbivax(target_ulong address) } } -void helper_booke206_tlbilx0(target_ulong address) +void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address) { /* XXX missing LPID handling */ booke206_flush_tlb(env, -1, 1); } -void helper_booke206_tlbilx1(target_ulong address) +void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address) { int i, j; int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID); @@ -825,7 +828,7 @@ void helper_booke206_tlbilx1(target_ulong address) tlb_flush(env, 1); } -void helper_booke206_tlbilx3(target_ulong address) +void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address) { int i, j; ppcmas_tlb_t *tlb; @@ -865,7 +868,7 @@ void helper_booke206_tlbilx3(target_ulong address) tlb_flush(env, 1); } -void helper_booke206_tlbflush(uint32_t type) +void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type) { int flags = 0; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index eb3cd5a792..446f97e065 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4200,7 +4200,7 @@ static void gen_mfsr(DisasContext *ctx) return; } t0 = tcg_const_tl(SR(ctx->opcode)); - gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0); + gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); #endif } @@ -4219,7 +4219,7 @@ static void gen_mfsrin(DisasContext *ctx) t0 = tcg_temp_new(); tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28); tcg_gen_andi_tl(t0, t0, 0xF); - gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0); + gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); #endif } @@ -4236,7 +4236,7 @@ static void gen_mtsr(DisasContext *ctx) return; } t0 = tcg_const_tl(SR(ctx->opcode)); - gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]); tcg_temp_free(t0); #endif } @@ -4255,7 +4255,7 @@ static void gen_mtsrin(DisasContext *ctx) t0 = tcg_temp_new(); tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28); tcg_gen_andi_tl(t0, t0, 0xF); - gen_helper_store_sr(t0, cpu_gpr[rD(ctx->opcode)]); + gen_helper_store_sr(cpu_env, t0, cpu_gpr[rD(ctx->opcode)]); tcg_temp_free(t0); #endif } @@ -4275,7 +4275,7 @@ static void gen_mfsr_64b(DisasContext *ctx) return; } t0 = tcg_const_tl(SR(ctx->opcode)); - gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0); + gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); #endif } @@ -4294,7 +4294,7 @@ static void gen_mfsrin_64b(DisasContext *ctx) t0 = tcg_temp_new(); tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28); tcg_gen_andi_tl(t0, t0, 0xF); - gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0); + gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); #endif } @@ -4311,7 +4311,7 @@ static void gen_mtsr_64b(DisasContext *ctx) return; } t0 = tcg_const_tl(SR(ctx->opcode)); - gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]); tcg_temp_free(t0); #endif } @@ -4330,7 +4330,7 @@ static void gen_mtsrin_64b(DisasContext *ctx) t0 = tcg_temp_new(); tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28); tcg_gen_andi_tl(t0, t0, 0xF); - gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]); tcg_temp_free(t0); #endif } @@ -4345,7 +4345,8 @@ static void gen_slbmte(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } - gen_helper_store_slb(cpu_gpr[rB(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_slb(cpu_env, cpu_gpr[rB(ctx->opcode)], + cpu_gpr[rS(ctx->opcode)]); #endif } @@ -4358,7 +4359,7 @@ static void gen_slbmfee(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } - gen_helper_load_slb_esid(cpu_gpr[rS(ctx->opcode)], + gen_helper_load_slb_esid(cpu_gpr[rS(ctx->opcode)], cpu_env, cpu_gpr[rB(ctx->opcode)]); #endif } @@ -4372,7 +4373,7 @@ static void gen_slbmfev(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); return; } - gen_helper_load_slb_vsid(cpu_gpr[rS(ctx->opcode)], + gen_helper_load_slb_vsid(cpu_gpr[rS(ctx->opcode)], cpu_env, cpu_gpr[rB(ctx->opcode)]); #endif } @@ -4391,7 +4392,7 @@ static void gen_tlbia(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } - gen_helper_tlbia(); + gen_helper_tlbia(cpu_env); #endif } @@ -4405,7 +4406,7 @@ static void gen_tlbiel(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } - gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]); + gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); #endif } @@ -4423,11 +4424,11 @@ static void gen_tlbie(DisasContext *ctx) if (!ctx->sf_mode) { TCGv t0 = tcg_temp_new(); tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]); - gen_helper_tlbie(t0); + gen_helper_tlbie(cpu_env, t0); tcg_temp_free(t0); } else #endif - gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]); + gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); #endif } @@ -4459,7 +4460,7 @@ static void gen_slbia(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } - gen_helper_slbia(); + gen_helper_slbia(cpu_env); #endif } @@ -4473,7 +4474,7 @@ static void gen_slbie(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } - gen_helper_slbie(cpu_gpr[rB(ctx->opcode)]); + gen_helper_slbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); #endif } #endif @@ -5194,7 +5195,7 @@ static void gen_tlbld_6xx(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } - gen_helper_6xx_tlbd(cpu_gpr[rB(ctx->opcode)]); + gen_helper_6xx_tlbd(cpu_env, cpu_gpr[rB(ctx->opcode)]); #endif } @@ -5208,7 +5209,7 @@ static void gen_tlbli_6xx(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } - gen_helper_6xx_tlbi(cpu_gpr[rB(ctx->opcode)]); + gen_helper_6xx_tlbi(cpu_env, cpu_gpr[rB(ctx->opcode)]); #endif } @@ -5224,7 +5225,7 @@ static void gen_tlbld_74xx(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } - gen_helper_74xx_tlbd(cpu_gpr[rB(ctx->opcode)]); + gen_helper_74xx_tlbd(cpu_env, cpu_gpr[rB(ctx->opcode)]); #endif } @@ -5238,7 +5239,7 @@ static void gen_tlbli_74xx(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } - gen_helper_74xx_tlbi(cpu_gpr[rB(ctx->opcode)]); + gen_helper_74xx_tlbi(cpu_env, cpu_gpr[rB(ctx->opcode)]); #endif } @@ -5286,7 +5287,7 @@ static void gen_mfsri(DisasContext *ctx) gen_addr_reg_index(ctx, t0); tcg_gen_shri_tl(t0, t0, 28); tcg_gen_andi_tl(t0, t0, 0xF); - gen_helper_load_sr(cpu_gpr[rd], t0); + gen_helper_load_sr(cpu_gpr[rd], cpu_env, t0); tcg_temp_free(t0); if (ra != 0 && ra != rd) tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rd]); @@ -5305,7 +5306,7 @@ static void gen_rac(DisasContext *ctx) } t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_rac(cpu_gpr[rD(ctx->opcode)], t0); + gen_helper_rac(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); #endif } @@ -5483,7 +5484,7 @@ static void gen_tlbiva(DisasContext *ctx) } t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]); + gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); tcg_temp_free(t0); #endif } @@ -5946,10 +5947,12 @@ static void gen_tlbre_40x(DisasContext *ctx) } switch (rB(ctx->opcode)) { case 0: - gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_env, + cpu_gpr[rA(ctx->opcode)]); break; case 1: - gen_helper_4xx_tlbre_lo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + gen_helper_4xx_tlbre_lo(cpu_gpr[rD(ctx->opcode)], cpu_env, + cpu_gpr[rA(ctx->opcode)]); break; default: gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); @@ -5971,7 +5974,7 @@ static void gen_tlbsx_40x(DisasContext *ctx) } t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], t0); + gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); if (Rc(ctx->opcode)) { int l1 = gen_new_label(); @@ -5997,10 +6000,12 @@ static void gen_tlbwe_40x(DisasContext *ctx) } switch (rB(ctx->opcode)) { case 0: - gen_helper_4xx_tlbwe_hi(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + gen_helper_4xx_tlbwe_hi(cpu_env, cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rS(ctx->opcode)]); break; case 1: - gen_helper_4xx_tlbwe_lo(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + gen_helper_4xx_tlbwe_lo(cpu_env, cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rS(ctx->opcode)]); break; default: gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); @@ -6027,7 +6032,8 @@ static void gen_tlbre_440(DisasContext *ctx) case 2: { TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode)); - gen_helper_440_tlbre(cpu_gpr[rD(ctx->opcode)], t0, cpu_gpr[rA(ctx->opcode)]); + gen_helper_440_tlbre(cpu_gpr[rD(ctx->opcode)], cpu_env, + t0, cpu_gpr[rA(ctx->opcode)]); tcg_temp_free_i32(t0); } break; @@ -6051,7 +6057,7 @@ static void gen_tlbsx_440(DisasContext *ctx) } t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], t0); + gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free(t0); if (Rc(ctx->opcode)) { int l1 = gen_new_label(); @@ -6081,7 +6087,8 @@ static void gen_tlbwe_440(DisasContext *ctx) case 2: { TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode)); - gen_helper_440_tlbwe(t0, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + gen_helper_440_tlbwe(cpu_env, t0, cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rS(ctx->opcode)]); tcg_temp_free_i32(t0); } break; @@ -6105,7 +6112,7 @@ static void gen_tlbre_booke206(DisasContext *ctx) return; } - gen_helper_booke206_tlbre(); + gen_helper_booke206_tlbre(cpu_env); #endif } @@ -6129,7 +6136,7 @@ static void gen_tlbsx_booke206(DisasContext *ctx) } tcg_gen_add_tl(t0, t0, cpu_gpr[rB(ctx->opcode)]); - gen_helper_booke206_tlbsx(t0); + gen_helper_booke206_tlbsx(cpu_env, t0); #endif } @@ -6144,7 +6151,7 @@ static void gen_tlbwe_booke206(DisasContext *ctx) return; } gen_update_nip(ctx, ctx->nip - 4); - gen_helper_booke206_tlbwe(); + gen_helper_booke206_tlbwe(cpu_env); #endif } @@ -6162,7 +6169,7 @@ static void gen_tlbivax_booke206(DisasContext *ctx) t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_booke206_tlbivax(t0); + gen_helper_booke206_tlbivax(cpu_env, t0); #endif } @@ -6182,13 +6189,13 @@ static void gen_tlbilx_booke206(DisasContext *ctx) switch((ctx->opcode >> 21) & 0x3) { case 0: - gen_helper_booke206_tlbilx0(t0); + gen_helper_booke206_tlbilx0(cpu_env, t0); break; case 1: - gen_helper_booke206_tlbilx1(t0); + gen_helper_booke206_tlbilx1(cpu_env, t0); break; case 3: - gen_helper_booke206_tlbilx3(t0); + gen_helper_booke206_tlbilx3(cpu_env, t0); break; default: gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 6f61175e7d..1e15fd9aef 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -279,28 +279,28 @@ static void spr_read_ibat_h (void *opaque, int gprn, int sprn) static void spr_write_ibatu (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2); - gen_helper_store_ibatu(t0, cpu_gpr[gprn]); + gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } static void spr_write_ibatu_h (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4U) / 2) + 4); - gen_helper_store_ibatu(t0, cpu_gpr[gprn]); + gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } static void spr_write_ibatl (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0L) / 2); - gen_helper_store_ibatl(t0, cpu_gpr[gprn]); + gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } static void spr_write_ibatl_h (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4L) / 2) + 4); - gen_helper_store_ibatl(t0, cpu_gpr[gprn]); + gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } @@ -319,28 +319,28 @@ static void spr_read_dbat_h (void *opaque, int gprn, int sprn) static void spr_write_dbatu (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0U) / 2); - gen_helper_store_dbatu(t0, cpu_gpr[gprn]); + gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } static void spr_write_dbatu_h (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4U) / 2) + 4); - gen_helper_store_dbatu(t0, cpu_gpr[gprn]); + gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } static void spr_write_dbatl (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0L) / 2); - gen_helper_store_dbatl(t0, cpu_gpr[gprn]); + gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } static void spr_write_dbatl_h (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4L) / 2) + 4); - gen_helper_store_dbatl(t0, cpu_gpr[gprn]); + gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } @@ -421,14 +421,14 @@ static void spr_read_601_ubat (void *opaque, int gprn, int sprn) static void spr_write_601_ubatu (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2); - gen_helper_store_601_batl(t0, cpu_gpr[gprn]); + gen_helper_store_601_batl(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } static void spr_write_601_ubatl (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2); - gen_helper_store_601_batu(t0, cpu_gpr[gprn]); + gen_helper_store_601_batu(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } #endif @@ -1371,14 +1371,14 @@ static void spr_write_e500_l1csr0 (void *opaque, int sprn, int gprn) static void spr_write_booke206_mmucsr0 (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32(sprn); - gen_helper_booke206_tlbflush(t0); + gen_helper_booke206_tlbflush(cpu_env, t0); tcg_temp_free_i32(t0); } static void spr_write_booke_pid (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32(sprn); - gen_helper_booke_setpid(t0, cpu_gpr[gprn]); + gen_helper_booke_setpid(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } #endif From 4cc2cc085586cdb787a24d78a7ba032fa657275a Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:32 +0000 Subject: [PATCH 12/72] ppc: Avoid a warning with the next patch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the code is moved together by the next patch, compiler detects a possible uninitialized variable use. Avoid the warning by initializing the variables. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/mmu_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 7bd6230d08..e79b8f284f 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -89,7 +89,7 @@ void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb) { - target_ulong rt; + target_ulong rt = 0; if (ppc_load_slb_esid(env, rb, &rt) < 0) { helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, @@ -100,7 +100,7 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb) target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb) { - target_ulong rt; + target_ulong rt = 0; if (ppc_load_slb_vsid(env, rb, &rt) < 0) { helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, From 8cbbe3851c0ed3dad2231245e47bad5acf9e2a9a Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:33 +0000 Subject: [PATCH 13/72] ppc: Move MMU helpers from helper.c to mmu_helper.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move more MMU helpers from helper.c to mmu_helper.c. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber [update to current helper.c state] Signed-off-by: Alexander Graf --- target-ppc/helper.c | 2475 --------------------------------------- target-ppc/mmu_helper.c | 2471 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 2471 insertions(+), 2475 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 17e72a9013..24d109d992 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -23,2483 +23,8 @@ #include "kvm_ppc.h" #include "cpus.h" -//#define DEBUG_MMU -//#define DEBUG_BATS -//#define DEBUG_SLB -//#define DEBUG_SOFTWARE_TLB -//#define DUMP_PAGE_TABLES -//#define FLUSH_ALL_TLBS - -#ifdef DEBUG_MMU -# define LOG_MMU(...) qemu_log(__VA_ARGS__) -# define LOG_MMU_STATE(env) log_cpu_state((env), 0) -#else -# define LOG_MMU(...) do { } while (0) -# define LOG_MMU_STATE(...) do { } while (0) -#endif - - -#ifdef DEBUG_SOFTWARE_TLB -# define LOG_SWTLB(...) qemu_log(__VA_ARGS__) -#else -# define LOG_SWTLB(...) do { } while (0) -#endif - -#ifdef DEBUG_BATS -# define LOG_BATS(...) qemu_log(__VA_ARGS__) -#else -# define LOG_BATS(...) do { } while (0) -#endif - -#ifdef DEBUG_SLB -# define LOG_SLB(...) qemu_log(__VA_ARGS__) -#else -# define LOG_SLB(...) do { } while (0) -#endif - -/*****************************************************************************/ -/* PowerPC MMU emulation */ - -#if defined(CONFIG_USER_ONLY) -int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, - int mmu_idx) -{ - int exception, error_code; - - if (rw == 2) { - exception = POWERPC_EXCP_ISI; - error_code = 0x40000000; - } else { - exception = POWERPC_EXCP_DSI; - error_code = 0x40000000; - if (rw) { - error_code |= 0x02000000; - } - env->spr[SPR_DAR] = address; - env->spr[SPR_DSISR] = error_code; - } - env->exception_index = exception; - env->error_code = error_code; - - return 1; -} - -#else -/* Common routines used by software and hardware TLBs emulation */ -static inline int pte_is_valid(target_ulong pte0) -{ - return pte0 & 0x80000000 ? 1 : 0; -} - -static inline void pte_invalidate(target_ulong *pte0) -{ - *pte0 &= ~0x80000000; -} - -#if defined(TARGET_PPC64) -static inline int pte64_is_valid(target_ulong pte0) -{ - return pte0 & 0x0000000000000001ULL ? 1 : 0; -} - -static inline void pte64_invalidate(target_ulong *pte0) -{ - *pte0 &= ~0x0000000000000001ULL; -} -#endif - -#define PTE_PTEM_MASK 0x7FFFFFBF -#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B) -#if defined(TARGET_PPC64) -#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL -#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F) -#endif - -static inline int pp_check(int key, int pp, int nx) -{ - int access; - - /* Compute access rights */ - /* When pp is 3/7, the result is undefined. Set it to noaccess */ - access = 0; - if (key == 0) { - switch (pp) { - case 0x0: - case 0x1: - case 0x2: - access |= PAGE_WRITE; - /* No break here */ - case 0x3: - case 0x6: - access |= PAGE_READ; - break; - } - } else { - switch (pp) { - case 0x0: - case 0x6: - access = 0; - break; - case 0x1: - case 0x3: - access = PAGE_READ; - break; - case 0x2: - access = PAGE_READ | PAGE_WRITE; - break; - } - } - if (nx == 0) { - access |= PAGE_EXEC; - } - - return access; -} - -static inline int check_prot(int prot, int rw, int access_type) -{ - int ret; - - if (access_type == ACCESS_CODE) { - if (prot & PAGE_EXEC) { - ret = 0; - } else { - ret = -2; - } - } else if (rw) { - if (prot & PAGE_WRITE) { - ret = 0; - } else { - ret = -2; - } - } else { - if (prot & PAGE_READ) { - ret = 0; - } else { - ret = -2; - } - } - - return ret; -} - -static inline int pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0, - target_ulong pte1, int h, int rw, int type) -{ - target_ulong ptem, mmask; - int access, ret, pteh, ptev, pp; - - ret = -1; - /* Check validity and table match */ -#if defined(TARGET_PPC64) - if (is_64b) { - ptev = pte64_is_valid(pte0); - pteh = (pte0 >> 1) & 1; - } else -#endif - { - ptev = pte_is_valid(pte0); - pteh = (pte0 >> 6) & 1; - } - if (ptev && h == pteh) { - /* Check vsid & api */ -#if defined(TARGET_PPC64) - if (is_64b) { - ptem = pte0 & PTE64_PTEM_MASK; - mmask = PTE64_CHECK_MASK; - pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004); - ctx->nx = (pte1 >> 2) & 1; /* No execute bit */ - ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */ - } else -#endif - { - ptem = pte0 & PTE_PTEM_MASK; - mmask = PTE_CHECK_MASK; - pp = pte1 & 0x00000003; - } - if (ptem == ctx->ptem) { - if (ctx->raddr != (target_phys_addr_t)-1ULL) { - /* all matches should have equal RPN, WIMG & PP */ - if ((ctx->raddr & mmask) != (pte1 & mmask)) { - qemu_log("Bad RPN/WIMG/PP\n"); - return -3; - } - } - /* Compute access rights */ - access = pp_check(ctx->key, pp, ctx->nx); - /* Keep the matching PTE informations */ - ctx->raddr = pte1; - ctx->prot = access; - ret = check_prot(ctx->prot, rw, type); - if (ret == 0) { - /* Access granted */ - LOG_MMU("PTE access granted !\n"); - } else { - /* Access right violation */ - LOG_MMU("PTE access rejected\n"); - } - } - } - - return ret; -} - -static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0, - target_ulong pte1, int h, int rw, int type) -{ - return pte_check(ctx, 0, pte0, pte1, h, rw, type); -} - -#if defined(TARGET_PPC64) -static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0, - target_ulong pte1, int h, int rw, int type) -{ - return pte_check(ctx, 1, pte0, pte1, h, rw, type); -} -#endif - -static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, - int ret, int rw) -{ - int store = 0; - - /* Update page flags */ - if (!(*pte1p & 0x00000100)) { - /* Update accessed flag */ - *pte1p |= 0x00000100; - store = 1; - } - if (!(*pte1p & 0x00000080)) { - if (rw == 1 && ret == 0) { - /* Update changed flag */ - *pte1p |= 0x00000080; - store = 1; - } else { - /* Force page fault for first write access */ - ctx->prot &= ~PAGE_WRITE; - } - } - - return store; -} - -/* Software driven TLB helpers */ -static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr, - int way, int is_code) -{ - int nr; - - /* Select TLB num in a way from address */ - nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1); - /* Select TLB way */ - nr += env->tlb_per_way * way; - /* 6xx have separate TLBs for instructions and data */ - if (is_code && env->id_tlbs == 1) { - nr += env->nb_tlb; - } - - return nr; -} - -static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env) -{ - ppc6xx_tlb_t *tlb; - int nr, max; - - /* LOG_SWTLB("Invalidate all TLBs\n"); */ - /* Invalidate all defined software TLB */ - max = env->nb_tlb; - if (env->id_tlbs == 1) { - max *= 2; - } - for (nr = 0; nr < max; nr++) { - tlb = &env->tlb.tlb6[nr]; - pte_invalidate(&tlb->pte0); - } - tlb_flush(env, 1); -} - -static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env, - target_ulong eaddr, - int is_code, int match_epn) -{ -#if !defined(FLUSH_ALL_TLBS) - ppc6xx_tlb_t *tlb; - int way, nr; - - /* Invalidate ITLB + DTLB, all ways */ - for (way = 0; way < env->nb_ways; way++) { - nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code); - tlb = &env->tlb.tlb6[nr]; - if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) { - LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr, - env->nb_tlb, eaddr); - pte_invalidate(&tlb->pte0); - tlb_flush_page(env, tlb->EPN); - } - } -#else - /* XXX: PowerPC specification say this is valid as well */ - ppc6xx_tlb_invalidate_all(env); -#endif -} - -static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env, - target_ulong eaddr, int is_code) -{ - ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0); -} - -void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, int is_code, - target_ulong pte0, target_ulong pte1) -{ - ppc6xx_tlb_t *tlb; - int nr; - - nr = ppc6xx_tlb_getnum(env, EPN, way, is_code); - tlb = &env->tlb.tlb6[nr]; - LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx - " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1); - /* Invalidate any pending reference in QEMU for this virtual address */ - ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1); - tlb->pte0 = pte0; - tlb->pte1 = pte1; - tlb->EPN = EPN; - /* Store last way for LRU mechanism */ - env->last_way = way; -} - -static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw, int access_type) -{ - ppc6xx_tlb_t *tlb; - int nr, best, way; - int ret; - - best = -1; - ret = -1; /* No TLB found */ - for (way = 0; way < env->nb_ways; way++) { - nr = ppc6xx_tlb_getnum(env, eaddr, way, - access_type == ACCESS_CODE ? 1 : 0); - tlb = &env->tlb.tlb6[nr]; - /* This test "emulates" the PTE index match for hardware TLBs */ - if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) { - LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx - "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb, - pte_is_valid(tlb->pte0) ? "valid" : "inval", - tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr); - continue; - } - LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " " - TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb, - pte_is_valid(tlb->pte0) ? "valid" : "inval", - tlb->EPN, eaddr, tlb->pte1, - rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D'); - switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) { - case -3: - /* TLB inconsistency */ - return -1; - case -2: - /* Access violation */ - ret = -2; - best = nr; - break; - case -1: - default: - /* No match */ - break; - case 0: - /* access granted */ - /* XXX: we should go on looping to check all TLBs consistency - * but we can speed-up the whole thing as the - * result would be undefined if TLBs are not consistent. - */ - ret = 0; - best = nr; - goto done; - } - } - if (best != -1) { - done: - LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n", - ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret); - /* Update page flags */ - pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw); - } - - return ret; -} - -/* Perform BAT hit & translation */ -static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp, - int *validp, int *protp, target_ulong *BATu, - target_ulong *BATl) -{ - target_ulong bl; - int pp, valid, prot; - - bl = (*BATu & 0x00001FFC) << 15; - valid = 0; - prot = 0; - if (((msr_pr == 0) && (*BATu & 0x00000002)) || - ((msr_pr != 0) && (*BATu & 0x00000001))) { - valid = 1; - pp = *BATl & 0x00000003; - if (pp != 0) { - prot = PAGE_READ | PAGE_EXEC; - if (pp == 0x2) { - prot |= PAGE_WRITE; - } - } - } - *blp = bl; - *validp = valid; - *protp = prot; -} - -static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp, - int *validp, int *protp, - target_ulong *BATu, target_ulong *BATl) -{ - target_ulong bl; - int key, pp, valid, prot; - - bl = (*BATl & 0x0000003F) << 17; - LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n", - (uint8_t)(*BATl & 0x0000003F), bl, ~bl); - prot = 0; - valid = (*BATl >> 6) & 1; - if (valid) { - pp = *BATu & 0x00000003; - if (msr_pr == 0) { - key = (*BATu >> 3) & 1; - } else { - key = (*BATu >> 2) & 1; - } - prot = pp_check(key, pp, 0); - } - *blp = bl; - *validp = valid; - *protp = prot; -} - -static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong virtual, int rw, int type) -{ - target_ulong *BATlt, *BATut, *BATu, *BATl; - target_ulong BEPIl, BEPIu, bl; - int i, valid, prot; - int ret = -1; - - LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', virtual); - switch (type) { - case ACCESS_CODE: - BATlt = env->IBAT[1]; - BATut = env->IBAT[0]; - break; - default: - BATlt = env->DBAT[1]; - BATut = env->DBAT[0]; - break; - } - for (i = 0; i < env->nb_BATs; i++) { - BATu = &BATut[i]; - BATl = &BATlt[i]; - BEPIu = *BATu & 0xF0000000; - BEPIl = *BATu & 0x0FFE0000; - if (unlikely(env->mmu_model == POWERPC_MMU_601)) { - bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl); - } else { - bat_size_prot(env, &bl, &valid, &prot, BATu, BATl); - } - LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx - " BATl " TARGET_FMT_lx "\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl); - if ((virtual & 0xF0000000) == BEPIu && - ((virtual & 0x0FFE0000) & ~bl) == BEPIl) { - /* BAT matches */ - if (valid != 0) { - /* Get physical address */ - ctx->raddr = (*BATl & 0xF0000000) | - ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | - (virtual & 0x0001F000); - /* Compute access rights */ - ctx->prot = prot; - ret = check_prot(ctx->prot, rw, type); - if (ret == 0) { - LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n", - i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', - ctx->prot & PAGE_WRITE ? 'W' : '-'); - } - break; - } - } - } - if (ret < 0) { -#if defined(DEBUG_BATS) - if (qemu_log_enabled()) { - LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual); - for (i = 0; i < 4; i++) { - BATu = &BATut[i]; - BATl = &BATlt[i]; - BEPIu = *BATu & 0xF0000000; - BEPIl = *BATu & 0x0FFE0000; - bl = (*BATu & 0x00001FFC) << 15; - LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx - " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " " - TARGET_FMT_lx " " TARGET_FMT_lx "\n", - __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, - *BATu, *BATl, BEPIu, BEPIl, bl); - } - } -#endif - } - /* No hit */ - return ret; -} - -static inline target_phys_addr_t get_pteg_offset(CPUPPCState *env, - target_phys_addr_t hash, - int pte_size) -{ - return (hash * pte_size * 8) & env->htab_mask; -} - -/* PTE table lookup */ -static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, - int rw, int type, int target_page_bits) -{ - target_phys_addr_t pteg_off; - target_ulong pte0, pte1; - int i, good = -1; - int ret, r; - - ret = -1; /* No entry found */ - pteg_off = get_pteg_offset(env, ctx->hash[h], - is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32); - for (i = 0; i < 8; i++) { -#if defined(TARGET_PPC64) - if (is_64b) { - if (env->external_htab) { - pte0 = ldq_p(env->external_htab + pteg_off + (i * 16)); - pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8); - } else { - pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16)); - pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8); - } - - r = pte64_check(ctx, pte0, pte1, h, rw, type); - LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " - TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", - pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h, - (int)((pte0 >> 1) & 1), ctx->ptem); - } else -#endif - { - if (env->external_htab) { - pte0 = ldl_p(env->external_htab + pteg_off + (i * 8)); - pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4); - } else { - pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8)); - pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4); - } - r = pte32_check(ctx, pte0, pte1, h, rw, type); - LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " - TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", - pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h, - (int)((pte0 >> 6) & 1), ctx->ptem); - } - switch (r) { - case -3: - /* PTE inconsistency */ - return -1; - case -2: - /* Access violation */ - ret = -2; - good = i; - break; - case -1: - default: - /* No PTE match */ - break; - case 0: - /* access granted */ - /* XXX: we should go on looping to check all PTEs consistency - * but if we can speed-up the whole thing as the - * result would be undefined if PTEs are not consistent. - */ - ret = 0; - good = i; - goto done; - } - } - if (good != -1) { - done: - LOG_MMU("found PTE at addr " TARGET_FMT_lx " prot=%01x ret=%d\n", - ctx->raddr, ctx->prot, ret); - /* Update page flags */ - pte1 = ctx->raddr; - if (pte_update_flags(ctx, &pte1, ret, rw) == 1) { -#if defined(TARGET_PPC64) - if (is_64b) { - if (env->external_htab) { - stq_p(env->external_htab + pteg_off + (good * 16) + 8, - pte1); - } else { - stq_phys_notdirty(env->htab_base + pteg_off + - (good * 16) + 8, pte1); - } - } else -#endif - { - if (env->external_htab) { - stl_p(env->external_htab + pteg_off + (good * 8) + 4, - pte1); - } else { - stl_phys_notdirty(env->htab_base + pteg_off + - (good * 8) + 4, pte1); - } - } - } - } - - /* We have a TLB that saves 4K pages, so let's - * split a huge page to 4k chunks */ - if (target_page_bits != TARGET_PAGE_BITS) { - ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1)) - & TARGET_PAGE_MASK; - } - return ret; -} - -static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw, - int type, int target_page_bits) -{ -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { - return find_pte2(env, ctx, 1, h, rw, type, target_page_bits); - } -#endif - - return find_pte2(env, ctx, 0, h, rw, type, target_page_bits); -} - -#if defined(TARGET_PPC64) -static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr) -{ - uint64_t esid_256M, esid_1T; - int n; - - LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr); - - esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V; - esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V; - - for (n = 0; n < env->slb_nr; n++) { - ppc_slb_t *slb = &env->slb[n]; - - LOG_SLB("%s: slot %d %016" PRIx64 " %016" - PRIx64 "\n", __func__, n, slb->esid, slb->vsid); - /* We check for 1T matches on all MMUs here - if the MMU - * doesn't have 1T segment support, we will have prevented 1T - * entries from being inserted in the slbmte code. */ - if (((slb->esid == esid_256M) && - ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M)) - || ((slb->esid == esid_1T) && - ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) { - return slb; - } - } - - return NULL; -} - -void ppc_slb_invalidate_all(CPUPPCState *env) -{ - int n, do_invalidate; - - do_invalidate = 0; - /* XXX: Warning: slbia never invalidates the first segment */ - for (n = 1; n < env->slb_nr; n++) { - ppc_slb_t *slb = &env->slb[n]; - - if (slb->esid & SLB_ESID_V) { - slb->esid &= ~SLB_ESID_V; - /* XXX: given the fact that segment size is 256 MB or 1TB, - * and we still don't have a tlb_flush_mask(env, n, mask) - * in QEMU, we just invalidate all TLBs - */ - do_invalidate = 1; - } - } - if (do_invalidate) { - tlb_flush(env, 1); - } -} - -void ppc_slb_invalidate_one(CPUPPCState *env, uint64_t T0) -{ - ppc_slb_t *slb; - - slb = slb_lookup(env, T0); - if (!slb) { - return; - } - - if (slb->esid & SLB_ESID_V) { - slb->esid &= ~SLB_ESID_V; - - /* XXX: given the fact that segment size is 256 MB or 1TB, - * and we still don't have a tlb_flush_mask(env, n, mask) - * in QEMU, we just invalidate all TLBs - */ - tlb_flush(env, 1); - } -} - -int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) -{ - int slot = rb & 0xfff; - ppc_slb_t *slb = &env->slb[slot]; - - if (rb & (0x1000 - env->slb_nr)) { - return -1; /* Reserved bits set or slot too high */ - } - if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) { - return -1; /* Bad segment size */ - } - if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) { - return -1; /* 1T segment on MMU that doesn't support it */ - } - - /* Mask out the slot number as we store the entry */ - slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V); - slb->vsid = rs; - - LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64 - " %016" PRIx64 "\n", __func__, slot, rb, rs, - slb->esid, slb->vsid); - - return 0; -} - -int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, target_ulong *rt) -{ - int slot = rb & 0xfff; - ppc_slb_t *slb = &env->slb[slot]; - - if (slot >= env->slb_nr) { - return -1; - } - - *rt = slb->esid; - return 0; -} - -int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb, target_ulong *rt) -{ - int slot = rb & 0xfff; - ppc_slb_t *slb = &env->slb[slot]; - - if (slot >= env->slb_nr) { - return -1; - } - - *rt = slb->vsid; - return 0; -} -#endif /* defined(TARGET_PPC64) */ - -/* Perform segment based translation */ -static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw, int type) -{ - target_phys_addr_t hash; - target_ulong vsid; - int ds, pr, target_page_bits; - int ret, ret2; - - pr = msr_pr; - ctx->eaddr = eaddr; -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { - ppc_slb_t *slb; - target_ulong pageaddr; - int segment_bits; - - LOG_MMU("Check SLBs\n"); - slb = slb_lookup(env, eaddr); - if (!slb) { - return -5; - } - - if (slb->vsid & SLB_VSID_B) { - vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T; - segment_bits = 40; - } else { - vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT; - segment_bits = 28; - } - - target_page_bits = (slb->vsid & SLB_VSID_L) - ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS; - ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP) - : (slb->vsid & SLB_VSID_KS)); - ds = 0; - ctx->nx = !!(slb->vsid & SLB_VSID_N); - - pageaddr = eaddr & ((1ULL << segment_bits) - - (1ULL << target_page_bits)); - if (slb->vsid & SLB_VSID_B) { - hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits); - } else { - hash = vsid ^ (pageaddr >> target_page_bits); - } - /* Only 5 bits of the page index are used in the AVPN */ - ctx->ptem = (slb->vsid & SLB_VSID_PTEM) | - ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80)); - } else -#endif /* defined(TARGET_PPC64) */ - { - target_ulong sr, pgidx; - - sr = env->sr[eaddr >> 28]; - 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; - target_page_bits = TARGET_PAGE_BITS; - LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" - TARGET_FMT_lx " lr=" TARGET_FMT_lx - " ir=%d dr=%d pr=%d %d t=%d\n", - eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir, - (int)msr_dr, pr != 0 ? 1 : 0, rw, type); - pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits; - hash = vsid ^ pgidx; - ctx->ptem = (vsid << 7) | (pgidx >> 10); - } - LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n", - ctx->key, ds, ctx->nx, vsid); - ret = -1; - if (!ds) { - /* Check if instruction fetch is allowed, if needed */ - if (type != ACCESS_CODE || ctx->nx == 0) { - /* Page address translation */ - LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx - " hash " TARGET_FMT_plx "\n", - env->htab_base, env->htab_mask, hash); - ctx->hash[0] = hash; - ctx->hash[1] = ~hash; - - /* Initialize real address with an invalid value */ - ctx->raddr = (target_phys_addr_t)-1ULL; - if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx || - env->mmu_model == POWERPC_MMU_SOFT_74xx)) { - /* Software TLB search */ - ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); - } else { - LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx - " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx - " hash=" TARGET_FMT_plx "\n", - env->htab_base, env->htab_mask, vsid, ctx->ptem, - ctx->hash[0]); - /* Primary table lookup */ - ret = find_pte(env, ctx, 0, rw, type, target_page_bits); - if (ret < 0) { - /* Secondary table lookup */ - if (eaddr != 0xEFFFFFFF) { - LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx - " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx - " hash=" TARGET_FMT_plx "\n", env->htab_base, - env->htab_mask, vsid, ctx->ptem, ctx->hash[1]); - } - ret2 = find_pte(env, ctx, 1, rw, type, - target_page_bits); - if (ret2 != -1) { - ret = ret2; - } - } - } -#if defined(DUMP_PAGE_TABLES) - if (qemu_log_enabled()) { - target_phys_addr_t curaddr; - uint32_t a0, a1, a2, a3; - - qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx - "\n", sdr, mask + 0x80); - for (curaddr = sdr; curaddr < (sdr + mask + 0x80); - curaddr += 16) { - a0 = ldl_phys(curaddr); - a1 = ldl_phys(curaddr + 4); - a2 = ldl_phys(curaddr + 8); - a3 = ldl_phys(curaddr + 12); - if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) { - qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n", - curaddr, a0, a1, a2, a3); - } - } - } -#endif - } else { - LOG_MMU("No access allowed\n"); - ret = -3; - } - } else { - target_ulong sr; - - LOG_MMU("direct store...\n"); - /* Direct-store segment : absolutely *BUGGY* for now */ - - /* Direct-store implies a 32-bit MMU. - * Check the Segment Register's bus unit ID (BUID). - */ - sr = env->sr[eaddr >> 28]; - if ((sr & 0x1FF00000) >> 20 == 0x07f) { - /* Memory-forced I/O controller interface access */ - /* If T=1 and BUID=x'07F', the 601 performs a memory access - * to SR[28-31] LA[4-31], bypassing all protection mechanisms. - */ - ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF); - ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - return 0; - } - - switch (type) { - case ACCESS_INT: - /* Integer load/store : only access allowed */ - break; - case ACCESS_CODE: - /* No code fetch is allowed in direct-store areas */ - return -4; - case ACCESS_FLOAT: - /* Floating point load/store */ - return -4; - case ACCESS_RES: - /* lwarx, ldarx or srwcx. */ - return -4; - case ACCESS_CACHE: - /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */ - /* Should make the instruction do no-op. - * As it already do no-op, it's quite easy :-) - */ - ctx->raddr = eaddr; - return 0; - case ACCESS_EXT: - /* eciwx or ecowx */ - return -4; - default: - qemu_log("ERROR: instruction should not need " - "address translation\n"); - return -4; - } - if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) { - ctx->raddr = eaddr; - ret = 2; - } else { - ret = -2; - } - } - - return ret; -} - -/* Generic TLB check function for embedded PowerPC implementations */ -int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb, - target_phys_addr_t *raddrp, - target_ulong address, uint32_t pid, int ext, - int i) -{ - target_ulong mask; - - /* Check valid flag */ - if (!(tlb->prot & PAGE_VALID)) { - return -1; - } - mask = ~(tlb->size - 1); - LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx - " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN, - mask, (uint32_t)tlb->PID, tlb->prot); - /* Check PID */ - if (tlb->PID != 0 && tlb->PID != pid) { - return -1; - } - /* Check effective address */ - if ((address & mask) != tlb->EPN) { - return -1; - } - *raddrp = (tlb->RPN & mask) | (address & ~mask); -#if (TARGET_PHYS_ADDR_BITS >= 36) - if (ext) { - /* Extend the physical address to 36 bits */ - *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32; - } -#endif - - return 0; -} - -/* Generic TLB search function for PowerPC embedded implementations */ -int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid) -{ - ppcemb_tlb_t *tlb; - target_phys_addr_t raddr; - int i, ret; - - /* Default return value is no match */ - ret = -1; - for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb.tlbe[i]; - if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) { - ret = i; - break; - } - } - - return ret; -} - -/* Helpers specific to PowerPC 40x implementations */ -static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env) -{ - ppcemb_tlb_t *tlb; - int i; - - for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb.tlbe[i]; - tlb->prot &= ~PAGE_VALID; - } - tlb_flush(env, 1); -} - -static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env, - target_ulong eaddr, uint32_t pid) -{ -#if !defined(FLUSH_ALL_TLBS) - ppcemb_tlb_t *tlb; - target_phys_addr_t raddr; - target_ulong page, end; - int i; - - for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb.tlbe[i]; - if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) { - end = tlb->EPN + tlb->size; - for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { - tlb_flush_page(env, page); - } - tlb->prot &= ~PAGE_VALID; - break; - } - } -#else - ppc4xx_tlb_invalidate_all(env); -#endif -} - -static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong address, int rw, - int access_type) -{ - ppcemb_tlb_t *tlb; - target_phys_addr_t raddr; - int i, ret, zsel, zpr, pr; - - ret = -1; - raddr = (target_phys_addr_t)-1ULL; - pr = msr_pr; - for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb.tlbe[i]; - if (ppcemb_tlb_check(env, tlb, &raddr, address, - env->spr[SPR_40x_PID], 0, i) < 0) { - continue; - } - zsel = (tlb->attr >> 4) & 0xF; - zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3; - LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n", - __func__, i, zsel, zpr, rw, tlb->attr); - /* Check execute enable bit */ - switch (zpr) { - case 0x2: - if (pr != 0) { - goto check_perms; - } - /* No break here */ - case 0x3: - /* All accesses granted */ - ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - ret = 0; - break; - case 0x0: - if (pr != 0) { - /* Raise Zone protection fault. */ - env->spr[SPR_40x_ESR] = 1 << 22; - ctx->prot = 0; - ret = -2; - break; - } - /* No break here */ - case 0x1: - check_perms: - /* Check from TLB entry */ - ctx->prot = tlb->prot; - ret = check_prot(ctx->prot, rw, access_type); - if (ret == -2) { - env->spr[SPR_40x_ESR] = 0; - } - break; - } - if (ret >= 0) { - ctx->raddr = raddr; - LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx - " %d %d\n", __func__, address, ctx->raddr, ctx->prot, - ret); - return 0; - } - } - LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx - " %d %d\n", __func__, address, raddr, ctx->prot, ret); - - return ret; -} - -void store_40x_sler(CPUPPCState *env, uint32_t val) -{ - /* XXX: TO BE FIXED */ - if (val != 0x00000000) { - cpu_abort(env, "Little-endian regions are not supported by now\n"); - } - env->spr[SPR_405_SLER] = val; -} - -static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb, - target_phys_addr_t *raddr, int *prot, - target_ulong address, int rw, - int access_type, int i) -{ - int ret, prot2; - - if (ppcemb_tlb_check(env, tlb, raddr, address, - env->spr[SPR_BOOKE_PID], - !env->nb_pids, i) >= 0) { - goto found_tlb; - } - - if (env->spr[SPR_BOOKE_PID1] && - ppcemb_tlb_check(env, tlb, raddr, address, - env->spr[SPR_BOOKE_PID1], 0, i) >= 0) { - goto found_tlb; - } - - if (env->spr[SPR_BOOKE_PID2] && - ppcemb_tlb_check(env, tlb, raddr, address, - env->spr[SPR_BOOKE_PID2], 0, i) >= 0) { - goto found_tlb; - } - - LOG_SWTLB("%s: TLB entry not found\n", __func__); - return -1; - -found_tlb: - - if (msr_pr != 0) { - prot2 = tlb->prot & 0xF; - } else { - prot2 = (tlb->prot >> 4) & 0xF; - } - - /* Check the address space */ - if (access_type == ACCESS_CODE) { - if (msr_ir != (tlb->attr & 1)) { - LOG_SWTLB("%s: AS doesn't match\n", __func__); - return -1; - } - - *prot = prot2; - if (prot2 & PAGE_EXEC) { - LOG_SWTLB("%s: good TLB!\n", __func__); - return 0; - } - - LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2); - ret = -3; - } else { - if (msr_dr != (tlb->attr & 1)) { - LOG_SWTLB("%s: AS doesn't match\n", __func__); - return -1; - } - - *prot = prot2; - if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) { - LOG_SWTLB("%s: found TLB!\n", __func__); - return 0; - } - - LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2); - ret = -2; - } - - return ret; -} - -static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong address, int rw, - int access_type) -{ - ppcemb_tlb_t *tlb; - target_phys_addr_t raddr; - int i, ret; - - ret = -1; - raddr = (target_phys_addr_t)-1ULL; - for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb.tlbe[i]; - ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw, - access_type, i); - if (!ret) { - break; - } - } - - if (ret >= 0) { - ctx->raddr = raddr; - LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx - " %d %d\n", __func__, address, ctx->raddr, ctx->prot, - ret); - } else { - LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx - " %d %d\n", __func__, address, raddr, ctx->prot, ret); - } - - return ret; -} - -void booke206_flush_tlb(CPUPPCState *env, int flags, const int check_iprot) -{ - int tlb_size; - int i, j; - ppcmas_tlb_t *tlb = env->tlb.tlbm; - - for (i = 0; i < BOOKE206_MAX_TLBN; i++) { - if (flags & (1 << i)) { - tlb_size = booke206_tlb_size(env, i); - for (j = 0; j < tlb_size; j++) { - if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) { - tlb[j].mas1 &= ~MAS1_VALID; - } - } - } - tlb += booke206_tlb_size(env, i); - } - - tlb_flush(env, 1); -} - -target_phys_addr_t booke206_tlb_to_page_size(CPUPPCState *env, - ppcmas_tlb_t *tlb) -{ - int tlbm_size; - - tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; - - return 1024ULL << tlbm_size; -} - -/* TLB check function for MAS based SoftTLBs */ -int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, - target_phys_addr_t *raddrp, - target_ulong address, uint32_t pid) -{ - target_ulong mask; - uint32_t tlb_pid; - - /* Check valid flag */ - if (!(tlb->mas1 & MAS1_VALID)) { - return -1; - } - - mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); - LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%" - PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n", - __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3, - tlb->mas8); - - /* Check PID */ - tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT; - if (tlb_pid != 0 && tlb_pid != pid) { - return -1; - } - - /* Check effective address */ - if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) { - return -1; - } - - if (raddrp) { - *raddrp = (tlb->mas7_3 & mask) | (address & ~mask); - } - - return 0; -} - -static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb, - target_phys_addr_t *raddr, int *prot, - target_ulong address, int rw, - int access_type) -{ - int ret; - int prot2 = 0; - - if (ppcmas_tlb_check(env, tlb, raddr, address, - env->spr[SPR_BOOKE_PID]) >= 0) { - goto found_tlb; - } - - if (env->spr[SPR_BOOKE_PID1] && - ppcmas_tlb_check(env, tlb, raddr, address, - env->spr[SPR_BOOKE_PID1]) >= 0) { - goto found_tlb; - } - - if (env->spr[SPR_BOOKE_PID2] && - ppcmas_tlb_check(env, tlb, raddr, address, - env->spr[SPR_BOOKE_PID2]) >= 0) { - goto found_tlb; - } - - LOG_SWTLB("%s: TLB entry not found\n", __func__); - return -1; - -found_tlb: - - if (msr_pr != 0) { - if (tlb->mas7_3 & MAS3_UR) { - prot2 |= PAGE_READ; - } - if (tlb->mas7_3 & MAS3_UW) { - prot2 |= PAGE_WRITE; - } - if (tlb->mas7_3 & MAS3_UX) { - prot2 |= PAGE_EXEC; - } - } else { - if (tlb->mas7_3 & MAS3_SR) { - prot2 |= PAGE_READ; - } - if (tlb->mas7_3 & MAS3_SW) { - prot2 |= PAGE_WRITE; - } - if (tlb->mas7_3 & MAS3_SX) { - prot2 |= PAGE_EXEC; - } - } - - /* Check the address space and permissions */ - if (access_type == ACCESS_CODE) { - if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { - LOG_SWTLB("%s: AS doesn't match\n", __func__); - return -1; - } - - *prot = prot2; - if (prot2 & PAGE_EXEC) { - LOG_SWTLB("%s: good TLB!\n", __func__); - return 0; - } - - LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2); - ret = -3; - } else { - if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { - LOG_SWTLB("%s: AS doesn't match\n", __func__); - return -1; - } - - *prot = prot2; - if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) { - LOG_SWTLB("%s: found TLB!\n", __func__); - return 0; - } - - LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2); - ret = -2; - } - - return ret; -} - -static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong address, int rw, - int access_type) -{ - ppcmas_tlb_t *tlb; - target_phys_addr_t raddr; - int i, j, ret; - - ret = -1; - raddr = (target_phys_addr_t)-1ULL; - - for (i = 0; i < BOOKE206_MAX_TLBN; i++) { - int ways = booke206_tlb_ways(env, i); - - for (j = 0; j < ways; j++) { - tlb = booke206_get_tlbm(env, i, address, j); - if (!tlb) { - continue; - } - ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address, - rw, access_type); - if (ret != -1) { - goto found_tlb; - } - } - } - -found_tlb: - - if (ret >= 0) { - ctx->raddr = raddr; - LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx - " %d %d\n", __func__, address, ctx->raddr, ctx->prot, - ret); - } else { - LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx - " %d %d\n", __func__, address, raddr, ctx->prot, ret); - } - - return ret; -} - -static const char *book3e_tsize_to_str[32] = { - "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K", - "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M", - "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G", - "1T", "2T" -}; - -static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf, - CPUPPCState *env) -{ - ppcemb_tlb_t *entry; - int i; - - if (kvm_enabled() && !env->kvm_sw_tlb) { - cpu_fprintf(f, "Cannot access KVM TLB\n"); - return; - } - - cpu_fprintf(f, "\nTLB:\n"); - cpu_fprintf(f, "Effective Physical Size PID Prot " - "Attr\n"); - - entry = &env->tlb.tlbe[0]; - for (i = 0; i < env->nb_tlb; i++, entry++) { - target_phys_addr_t ea, pa; - target_ulong mask; - uint64_t size = (uint64_t)entry->size; - char size_buf[20]; - - /* Check valid flag */ - if (!(entry->prot & PAGE_VALID)) { - continue; - } - - mask = ~(entry->size - 1); - ea = entry->EPN & mask; - pa = entry->RPN & mask; -#if (TARGET_PHYS_ADDR_BITS >= 36) - /* Extend the physical address to 36 bits */ - pa |= (target_phys_addr_t)(entry->RPN & 0xF) << 32; -#endif - size /= 1024; - if (size >= 1024) { - snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024); - } else { - snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size); - } - cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n", - (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID, - entry->prot, entry->attr); - } - -} - -static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf, - CPUPPCState *env, int tlbn, int offset, - int tlbsize) -{ - ppcmas_tlb_t *entry; - int i; - - cpu_fprintf(f, "\nTLB%d:\n", tlbn); - cpu_fprintf(f, "Effective Physical Size TID TS SRWX" - " URWX WIMGE U0123\n"); - - entry = &env->tlb.tlbm[offset]; - for (i = 0; i < tlbsize; i++, entry++) { - target_phys_addr_t ea, pa, size; - int tsize; - - if (!(entry->mas1 & MAS1_VALID)) { - continue; - } - - tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; - size = 1024ULL << tsize; - ea = entry->mas2 & ~(size - 1); - pa = entry->mas7_3 & ~(size - 1); - - cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c" - "U%c%c%c %c%c%c%c%c U%c%c%c%c\n", - (uint64_t)ea, (uint64_t)pa, - book3e_tsize_to_str[tsize], - (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT, - (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT, - entry->mas7_3 & MAS3_SR ? 'R' : '-', - entry->mas7_3 & MAS3_SW ? 'W' : '-', - entry->mas7_3 & MAS3_SX ? 'X' : '-', - entry->mas7_3 & MAS3_UR ? 'R' : '-', - entry->mas7_3 & MAS3_UW ? 'W' : '-', - entry->mas7_3 & MAS3_UX ? 'X' : '-', - entry->mas2 & MAS2_W ? 'W' : '-', - entry->mas2 & MAS2_I ? 'I' : '-', - entry->mas2 & MAS2_M ? 'M' : '-', - entry->mas2 & MAS2_G ? 'G' : '-', - entry->mas2 & MAS2_E ? 'E' : '-', - entry->mas7_3 & MAS3_U0 ? '0' : '-', - entry->mas7_3 & MAS3_U1 ? '1' : '-', - entry->mas7_3 & MAS3_U2 ? '2' : '-', - entry->mas7_3 & MAS3_U3 ? '3' : '-'); - } -} - -static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf, - CPUPPCState *env) -{ - int offset = 0; - int i; - - if (kvm_enabled() && !env->kvm_sw_tlb) { - cpu_fprintf(f, "Cannot access KVM TLB\n"); - return; - } - - for (i = 0; i < BOOKE206_MAX_TLBN; i++) { - int size = booke206_tlb_size(env, i); - - if (size == 0) { - continue; - } - - mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size); - offset += size; - } -} - -#if defined(TARGET_PPC64) -static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf, - CPUPPCState *env) -{ - int i; - uint64_t slbe, slbv; - - cpu_synchronize_state(env); - - cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n"); - for (i = 0; i < env->slb_nr; i++) { - slbe = env->slb[i].esid; - slbv = env->slb[i].vsid; - if (slbe == 0 && slbv == 0) { - continue; - } - cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n", - i, slbe, slbv); - } -} -#endif - -void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env) -{ - switch (env->mmu_model) { - case POWERPC_MMU_BOOKE: - mmubooke_dump_mmu(f, cpu_fprintf, env); - break; - case POWERPC_MMU_BOOKE206: - mmubooke206_dump_mmu(f, cpu_fprintf, env); - break; -#if defined(TARGET_PPC64) - case POWERPC_MMU_64B: - case POWERPC_MMU_2_06: - mmubooks_dump_mmu(f, cpu_fprintf, env); - break; -#endif - default: - qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__); - } -} - -static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw) -{ - int in_plb, ret; - - ctx->raddr = eaddr; - ctx->prot = PAGE_READ | PAGE_EXEC; - ret = 0; - switch (env->mmu_model) { - case POWERPC_MMU_32B: - case POWERPC_MMU_601: - case POWERPC_MMU_SOFT_6xx: - case POWERPC_MMU_SOFT_74xx: - case POWERPC_MMU_SOFT_4xx: - case POWERPC_MMU_REAL: - case POWERPC_MMU_BOOKE: - ctx->prot |= PAGE_WRITE; - break; -#if defined(TARGET_PPC64) - case POWERPC_MMU_620: - case POWERPC_MMU_64B: - case POWERPC_MMU_2_06: - /* Real address are 60 bits long */ - ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL; - ctx->prot |= PAGE_WRITE; - break; -#endif - case POWERPC_MMU_SOFT_4xx_Z: - if (unlikely(msr_pe != 0)) { - /* 403 family add some particular protections, - * using PBL/PBU registers for accesses with no translation. - */ - in_plb = - /* Check PLB validity */ - (env->pb[0] < env->pb[1] && - /* and address in plb area */ - eaddr >= env->pb[0] && eaddr < env->pb[1]) || - (env->pb[2] < env->pb[3] && - eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0; - if (in_plb ^ msr_px) { - /* Access in protected area */ - if (rw == 1) { - /* Access is not allowed */ - ret = -2; - } - } else { - /* Read-write access is allowed */ - ctx->prot |= PAGE_WRITE; - } - } - break; - case POWERPC_MMU_MPC8xx: - /* XXX: TODO */ - cpu_abort(env, "MPC8xx MMU model is not implemented\n"); - break; - case POWERPC_MMU_BOOKE206: - cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n"); - break; - default: - cpu_abort(env, "Unknown or invalid MMU model\n"); - return -1; - } - - return ret; -} - -int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr, - int rw, int access_type) -{ - int ret; - -#if 0 - qemu_log("%s\n", __func__); -#endif - if ((access_type == ACCESS_CODE && msr_ir == 0) || - (access_type != ACCESS_CODE && msr_dr == 0)) { - if (env->mmu_model == POWERPC_MMU_BOOKE) { - /* The BookE MMU always performs address translation. The - IS and DS bits only affect the address space. */ - ret = mmubooke_get_physical_address(env, ctx, eaddr, - rw, access_type); - } else if (env->mmu_model == POWERPC_MMU_BOOKE206) { - ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, - access_type); - } else { - /* No address translation. */ - ret = check_physical(env, ctx, eaddr, rw); - } - } else { - ret = -1; - switch (env->mmu_model) { - case POWERPC_MMU_32B: - case POWERPC_MMU_601: - case POWERPC_MMU_SOFT_6xx: - case POWERPC_MMU_SOFT_74xx: - /* Try to find a BAT */ - if (env->nb_BATs != 0) { - ret = get_bat(env, ctx, eaddr, rw, access_type); - } -#if defined(TARGET_PPC64) - case POWERPC_MMU_620: - case POWERPC_MMU_64B: - case POWERPC_MMU_2_06: -#endif - if (ret < 0) { - /* We didn't match any BAT entry or don't have BATs */ - ret = get_segment(env, ctx, eaddr, rw, access_type); - } - break; - case POWERPC_MMU_SOFT_4xx: - case POWERPC_MMU_SOFT_4xx_Z: - ret = mmu40x_get_physical_address(env, ctx, eaddr, - rw, access_type); - break; - case POWERPC_MMU_BOOKE: - ret = mmubooke_get_physical_address(env, ctx, eaddr, - rw, access_type); - break; - case POWERPC_MMU_BOOKE206: - ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, - access_type); - break; - case POWERPC_MMU_MPC8xx: - /* XXX: TODO */ - cpu_abort(env, "MPC8xx MMU model is not implemented\n"); - break; - case POWERPC_MMU_REAL: - cpu_abort(env, "PowerPC in real mode do not do any translation\n"); - return -1; - default: - cpu_abort(env, "Unknown or invalid MMU model\n"); - return -1; - } - } -#if 0 - qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n", - __func__, eaddr, ret, ctx->raddr); -#endif - - return ret; -} - -target_phys_addr_t cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr) -{ - mmu_ctx_t ctx; - - if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) { - return -1; - } - - return ctx.raddr & TARGET_PAGE_MASK; -} - -static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, - int rw) -{ - env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK; - env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK; - env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK; - env->spr[SPR_BOOKE_MAS3] = 0; - env->spr[SPR_BOOKE_MAS6] = 0; - env->spr[SPR_BOOKE_MAS7] = 0; - - /* AS */ - if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) { - env->spr[SPR_BOOKE_MAS1] |= MAS1_TS; - env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS; - } - - env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID; - env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK; - - switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) { - case MAS4_TIDSELD_PID0: - env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT; - break; - case MAS4_TIDSELD_PID1: - env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT; - break; - case MAS4_TIDSELD_PID2: - env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT; - break; - } - - env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16; - - /* next victim logic */ - env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT; - env->last_way++; - env->last_way &= booke206_tlb_ways(env, 0) - 1; - env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; -} - -/* Perform address translation */ -int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, - int mmu_idx) -{ - mmu_ctx_t ctx; - int access_type; - int ret = 0; - - if (rw == 2) { - /* code access */ - rw = 0; - access_type = ACCESS_CODE; - } else { - /* data access */ - access_type = env->access_type; - } - ret = get_physical_address(env, &ctx, address, rw, access_type); - if (ret == 0) { - tlb_set_page(env, address & TARGET_PAGE_MASK, - ctx.raddr & TARGET_PAGE_MASK, ctx.prot, - mmu_idx, TARGET_PAGE_SIZE); - ret = 0; - } else if (ret < 0) { - LOG_MMU_STATE(env); - if (access_type == ACCESS_CODE) { - switch (ret) { - case -1: - /* No matches in page tables or TLB */ - switch (env->mmu_model) { - case POWERPC_MMU_SOFT_6xx: - env->exception_index = POWERPC_EXCP_IFTLB; - env->error_code = 1 << 18; - env->spr[SPR_IMISS] = address; - env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem; - goto tlb_miss; - case POWERPC_MMU_SOFT_74xx: - env->exception_index = POWERPC_EXCP_IFTLB; - goto tlb_miss_74xx; - case POWERPC_MMU_SOFT_4xx: - case POWERPC_MMU_SOFT_4xx_Z: - env->exception_index = POWERPC_EXCP_ITLB; - env->error_code = 0; - env->spr[SPR_40x_DEAR] = address; - env->spr[SPR_40x_ESR] = 0x00000000; - break; - case POWERPC_MMU_32B: - case POWERPC_MMU_601: -#if defined(TARGET_PPC64) - case POWERPC_MMU_620: - case POWERPC_MMU_64B: - case POWERPC_MMU_2_06: -#endif - env->exception_index = POWERPC_EXCP_ISI; - env->error_code = 0x40000000; - break; - case POWERPC_MMU_BOOKE206: - booke206_update_mas_tlb_miss(env, address, rw); - /* fall through */ - case POWERPC_MMU_BOOKE: - env->exception_index = POWERPC_EXCP_ITLB; - env->error_code = 0; - env->spr[SPR_BOOKE_DEAR] = address; - return -1; - case POWERPC_MMU_MPC8xx: - /* XXX: TODO */ - cpu_abort(env, "MPC8xx MMU model is not implemented\n"); - break; - case POWERPC_MMU_REAL: - cpu_abort(env, "PowerPC in real mode should never raise " - "any MMU exceptions\n"); - return -1; - default: - cpu_abort(env, "Unknown or invalid MMU model\n"); - return -1; - } - break; - case -2: - /* Access rights violation */ - env->exception_index = POWERPC_EXCP_ISI; - env->error_code = 0x08000000; - break; - case -3: - /* No execute protection violation */ - if ((env->mmu_model == POWERPC_MMU_BOOKE) || - (env->mmu_model == POWERPC_MMU_BOOKE206)) { - env->spr[SPR_BOOKE_ESR] = 0x00000000; - } - env->exception_index = POWERPC_EXCP_ISI; - env->error_code = 0x10000000; - break; - case -4: - /* Direct store exception */ - /* No code fetch is allowed in direct-store areas */ - env->exception_index = POWERPC_EXCP_ISI; - env->error_code = 0x10000000; - break; -#if defined(TARGET_PPC64) - case -5: - /* No match in segment table */ - if (env->mmu_model == POWERPC_MMU_620) { - env->exception_index = POWERPC_EXCP_ISI; - /* XXX: this might be incorrect */ - env->error_code = 0x40000000; - } else { - env->exception_index = POWERPC_EXCP_ISEG; - env->error_code = 0; - } - break; -#endif - } - } else { - switch (ret) { - case -1: - /* No matches in page tables or TLB */ - switch (env->mmu_model) { - case POWERPC_MMU_SOFT_6xx: - if (rw == 1) { - env->exception_index = POWERPC_EXCP_DSTLB; - env->error_code = 1 << 16; - } else { - env->exception_index = POWERPC_EXCP_DLTLB; - env->error_code = 0; - } - env->spr[SPR_DMISS] = address; - env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem; - tlb_miss: - env->error_code |= ctx.key << 19; - env->spr[SPR_HASH1] = env->htab_base + - get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32); - env->spr[SPR_HASH2] = env->htab_base + - get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32); - break; - case POWERPC_MMU_SOFT_74xx: - if (rw == 1) { - env->exception_index = POWERPC_EXCP_DSTLB; - } else { - env->exception_index = POWERPC_EXCP_DLTLB; - } - tlb_miss_74xx: - /* Implement LRU algorithm */ - env->error_code = ctx.key << 19; - env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) | - ((env->last_way + 1) & (env->nb_ways - 1)); - env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem; - break; - case POWERPC_MMU_SOFT_4xx: - case POWERPC_MMU_SOFT_4xx_Z: - env->exception_index = POWERPC_EXCP_DTLB; - env->error_code = 0; - env->spr[SPR_40x_DEAR] = address; - if (rw) { - env->spr[SPR_40x_ESR] = 0x00800000; - } else { - env->spr[SPR_40x_ESR] = 0x00000000; - } - break; - case POWERPC_MMU_32B: - case POWERPC_MMU_601: -#if defined(TARGET_PPC64) - case POWERPC_MMU_620: - case POWERPC_MMU_64B: - case POWERPC_MMU_2_06: -#endif - env->exception_index = POWERPC_EXCP_DSI; - env->error_code = 0; - env->spr[SPR_DAR] = address; - if (rw == 1) { - env->spr[SPR_DSISR] = 0x42000000; - } else { - env->spr[SPR_DSISR] = 0x40000000; - } - break; - case POWERPC_MMU_MPC8xx: - /* XXX: TODO */ - cpu_abort(env, "MPC8xx MMU model is not implemented\n"); - break; - case POWERPC_MMU_BOOKE206: - booke206_update_mas_tlb_miss(env, address, rw); - /* fall through */ - case POWERPC_MMU_BOOKE: - env->exception_index = POWERPC_EXCP_DTLB; - env->error_code = 0; - env->spr[SPR_BOOKE_DEAR] = address; - env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0; - return -1; - case POWERPC_MMU_REAL: - cpu_abort(env, "PowerPC in real mode should never raise " - "any MMU exceptions\n"); - return -1; - default: - cpu_abort(env, "Unknown or invalid MMU model\n"); - return -1; - } - break; - case -2: - /* Access rights violation */ - env->exception_index = POWERPC_EXCP_DSI; - env->error_code = 0; - if (env->mmu_model == POWERPC_MMU_SOFT_4xx - || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) { - env->spr[SPR_40x_DEAR] = address; - if (rw) { - env->spr[SPR_40x_ESR] |= 0x00800000; - } - } else if ((env->mmu_model == POWERPC_MMU_BOOKE) || - (env->mmu_model == POWERPC_MMU_BOOKE206)) { - env->spr[SPR_BOOKE_DEAR] = address; - env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0; - } else { - env->spr[SPR_DAR] = address; - if (rw == 1) { - env->spr[SPR_DSISR] = 0x0A000000; - } else { - env->spr[SPR_DSISR] = 0x08000000; - } - } - break; - case -4: - /* Direct store exception */ - switch (access_type) { - case ACCESS_FLOAT: - /* Floating point load/store */ - env->exception_index = POWERPC_EXCP_ALIGN; - env->error_code = POWERPC_EXCP_ALIGN_FP; - env->spr[SPR_DAR] = address; - break; - case ACCESS_RES: - /* lwarx, ldarx or stwcx. */ - env->exception_index = POWERPC_EXCP_DSI; - env->error_code = 0; - env->spr[SPR_DAR] = address; - if (rw == 1) { - env->spr[SPR_DSISR] = 0x06000000; - } else { - env->spr[SPR_DSISR] = 0x04000000; - } - break; - case ACCESS_EXT: - /* eciwx or ecowx */ - env->exception_index = POWERPC_EXCP_DSI; - env->error_code = 0; - env->spr[SPR_DAR] = address; - if (rw == 1) { - env->spr[SPR_DSISR] = 0x06100000; - } else { - env->spr[SPR_DSISR] = 0x04100000; - } - break; - default: - printf("DSI: invalid exception (%d)\n", ret); - env->exception_index = POWERPC_EXCP_PROGRAM; - env->error_code = - POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL; - env->spr[SPR_DAR] = address; - break; - } - break; -#if defined(TARGET_PPC64) - case -5: - /* No match in segment table */ - if (env->mmu_model == POWERPC_MMU_620) { - env->exception_index = POWERPC_EXCP_DSI; - env->error_code = 0; - env->spr[SPR_DAR] = address; - /* XXX: this might be incorrect */ - if (rw == 1) { - env->spr[SPR_DSISR] = 0x42000000; - } else { - env->spr[SPR_DSISR] = 0x40000000; - } - } else { - env->exception_index = POWERPC_EXCP_DSEG; - env->error_code = 0; - env->spr[SPR_DAR] = address; - } - break; -#endif - } - } -#if 0 - printf("%s: set exception to %d %02x\n", __func__, - env->exception, env->error_code); -#endif - ret = 1; - } - - return ret; -} - -/*****************************************************************************/ -/* BATs management */ -#if !defined(FLUSH_ALL_TLBS) -static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu, - target_ulong mask) -{ - target_ulong base, end, page; - - base = BATu & ~0x0001FFFF; - end = base + mask + 0x00020000; - LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " (" - TARGET_FMT_lx ")\n", base, end, mask); - for (page = base; page != end; page += TARGET_PAGE_SIZE) { - tlb_flush_page(env, page); - } - LOG_BATS("Flush done\n"); -} -#endif - -static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr, - target_ulong value) -{ - LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID, - nr, ul == 0 ? 'u' : 'l', value, env->nip); -} - -void ppc_store_ibatu(CPUPPCState *env, int nr, target_ulong value) -{ - target_ulong mask; - - dump_store_bat(env, 'I', 0, nr, value); - if (env->IBAT[0][nr] != value) { - mask = (value << 15) & 0x0FFE0000UL; -#if !defined(FLUSH_ALL_TLBS) - do_invalidate_BAT(env, env->IBAT[0][nr], mask); -#endif - /* When storing valid upper BAT, mask BEPI and BRPN - * and invalidate all TLBs covered by this BAT - */ - mask = (value << 15) & 0x0FFE0000UL; - env->IBAT[0][nr] = (value & 0x00001FFFUL) | - (value & ~0x0001FFFFUL & ~mask); - env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) | - (env->IBAT[1][nr] & ~0x0001FFFF & ~mask); -#if !defined(FLUSH_ALL_TLBS) - do_invalidate_BAT(env, env->IBAT[0][nr], mask); -#else - tlb_flush(env, 1); -#endif - } -} - -void ppc_store_ibatl(CPUPPCState *env, int nr, target_ulong value) -{ - dump_store_bat(env, 'I', 1, nr, value); - env->IBAT[1][nr] = value; -} - -void ppc_store_dbatu(CPUPPCState *env, int nr, target_ulong value) -{ - target_ulong mask; - - dump_store_bat(env, 'D', 0, nr, value); - if (env->DBAT[0][nr] != value) { - /* When storing valid upper BAT, mask BEPI and BRPN - * and invalidate all TLBs covered by this BAT - */ - mask = (value << 15) & 0x0FFE0000UL; -#if !defined(FLUSH_ALL_TLBS) - do_invalidate_BAT(env, env->DBAT[0][nr], mask); -#endif - mask = (value << 15) & 0x0FFE0000UL; - env->DBAT[0][nr] = (value & 0x00001FFFUL) | - (value & ~0x0001FFFFUL & ~mask); - env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) | - (env->DBAT[1][nr] & ~0x0001FFFF & ~mask); -#if !defined(FLUSH_ALL_TLBS) - do_invalidate_BAT(env, env->DBAT[0][nr], mask); -#else - tlb_flush(env, 1); -#endif - } -} - -void ppc_store_dbatl(CPUPPCState *env, int nr, target_ulong value) -{ - dump_store_bat(env, 'D', 1, nr, value); - env->DBAT[1][nr] = value; -} - -void ppc_store_ibatu_601(CPUPPCState *env, int nr, target_ulong value) -{ - target_ulong mask; -#if defined(FLUSH_ALL_TLBS) - int do_inval; -#endif - - dump_store_bat(env, 'I', 0, nr, value); - if (env->IBAT[0][nr] != value) { -#if defined(FLUSH_ALL_TLBS) - do_inval = 0; -#endif - mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL; - if (env->IBAT[1][nr] & 0x40) { - /* Invalidate BAT only if it is valid */ -#if !defined(FLUSH_ALL_TLBS) - do_invalidate_BAT(env, env->IBAT[0][nr], mask); -#else - do_inval = 1; -#endif - } - /* When storing valid upper BAT, mask BEPI and BRPN - * and invalidate all TLBs covered by this BAT - */ - env->IBAT[0][nr] = (value & 0x00001FFFUL) | - (value & ~0x0001FFFFUL & ~mask); - env->DBAT[0][nr] = env->IBAT[0][nr]; - if (env->IBAT[1][nr] & 0x40) { -#if !defined(FLUSH_ALL_TLBS) - do_invalidate_BAT(env, env->IBAT[0][nr], mask); -#else - do_inval = 1; -#endif - } -#if defined(FLUSH_ALL_TLBS) - if (do_inval) { - tlb_flush(env, 1); - } -#endif - } -} - -void ppc_store_ibatl_601(CPUPPCState *env, int nr, target_ulong value) -{ - target_ulong mask; -#if defined(FLUSH_ALL_TLBS) - int do_inval; -#endif - - dump_store_bat(env, 'I', 1, nr, value); - if (env->IBAT[1][nr] != value) { -#if defined(FLUSH_ALL_TLBS) - do_inval = 0; -#endif - if (env->IBAT[1][nr] & 0x40) { -#if !defined(FLUSH_ALL_TLBS) - mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL; - do_invalidate_BAT(env, env->IBAT[0][nr], mask); -#else - do_inval = 1; -#endif - } - if (value & 0x40) { -#if !defined(FLUSH_ALL_TLBS) - mask = (value << 17) & 0x0FFE0000UL; - do_invalidate_BAT(env, env->IBAT[0][nr], mask); -#else - do_inval = 1; -#endif - } - env->IBAT[1][nr] = value; - env->DBAT[1][nr] = value; -#if defined(FLUSH_ALL_TLBS) - if (do_inval) { - tlb_flush(env, 1); - } -#endif - } -} - -/*****************************************************************************/ -/* TLB management */ -void ppc_tlb_invalidate_all(CPUPPCState *env) -{ - switch (env->mmu_model) { - case POWERPC_MMU_SOFT_6xx: - case POWERPC_MMU_SOFT_74xx: - ppc6xx_tlb_invalidate_all(env); - break; - case POWERPC_MMU_SOFT_4xx: - case POWERPC_MMU_SOFT_4xx_Z: - ppc4xx_tlb_invalidate_all(env); - break; - case POWERPC_MMU_REAL: - cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n"); - break; - case POWERPC_MMU_MPC8xx: - /* XXX: TODO */ - cpu_abort(env, "MPC8xx MMU model is not implemented\n"); - break; - case POWERPC_MMU_BOOKE: - tlb_flush(env, 1); - break; - case POWERPC_MMU_BOOKE206: - booke206_flush_tlb(env, -1, 0); - break; - case POWERPC_MMU_32B: - case POWERPC_MMU_601: -#if defined(TARGET_PPC64) - case POWERPC_MMU_620: - case POWERPC_MMU_64B: - case POWERPC_MMU_2_06: -#endif /* defined(TARGET_PPC64) */ - tlb_flush(env, 1); - break; - default: - /* XXX: TODO */ - cpu_abort(env, "Unknown MMU model\n"); - break; - } -} - -void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) -{ -#if !defined(FLUSH_ALL_TLBS) - addr &= TARGET_PAGE_MASK; - switch (env->mmu_model) { - case POWERPC_MMU_SOFT_6xx: - case POWERPC_MMU_SOFT_74xx: - ppc6xx_tlb_invalidate_virt(env, addr, 0); - if (env->id_tlbs == 1) { - ppc6xx_tlb_invalidate_virt(env, addr, 1); - } - break; - case POWERPC_MMU_SOFT_4xx: - case POWERPC_MMU_SOFT_4xx_Z: - ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]); - break; - case POWERPC_MMU_REAL: - cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n"); - break; - case POWERPC_MMU_MPC8xx: - /* XXX: TODO */ - cpu_abort(env, "MPC8xx MMU model is not implemented\n"); - break; - case POWERPC_MMU_BOOKE: - /* XXX: TODO */ - cpu_abort(env, "BookE MMU model is not implemented\n"); - break; - case POWERPC_MMU_BOOKE206: - /* XXX: TODO */ - cpu_abort(env, "BookE 2.06 MMU model is not implemented\n"); - break; - case POWERPC_MMU_32B: - case POWERPC_MMU_601: - /* tlbie invalidate TLBs for all segments */ - addr &= ~((target_ulong)-1ULL << 28); - /* XXX: this case should be optimized, - * giving a mask to tlb_flush_page - */ - tlb_flush_page(env, addr | (0x0 << 28)); - tlb_flush_page(env, addr | (0x1 << 28)); - tlb_flush_page(env, addr | (0x2 << 28)); - tlb_flush_page(env, addr | (0x3 << 28)); - tlb_flush_page(env, addr | (0x4 << 28)); - tlb_flush_page(env, addr | (0x5 << 28)); - tlb_flush_page(env, addr | (0x6 << 28)); - tlb_flush_page(env, addr | (0x7 << 28)); - tlb_flush_page(env, addr | (0x8 << 28)); - tlb_flush_page(env, addr | (0x9 << 28)); - tlb_flush_page(env, addr | (0xA << 28)); - tlb_flush_page(env, addr | (0xB << 28)); - tlb_flush_page(env, addr | (0xC << 28)); - tlb_flush_page(env, addr | (0xD << 28)); - tlb_flush_page(env, addr | (0xE << 28)); - tlb_flush_page(env, addr | (0xF << 28)); - break; -#if defined(TARGET_PPC64) - case POWERPC_MMU_620: - case POWERPC_MMU_64B: - case POWERPC_MMU_2_06: - /* tlbie invalidate TLBs for all segments */ - /* XXX: given the fact that there are too many segments to invalidate, - * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU, - * we just invalidate all TLBs - */ - tlb_flush(env, 1); - break; -#endif /* defined(TARGET_PPC64) */ - default: - /* XXX: TODO */ - cpu_abort(env, "Unknown MMU model\n"); - break; - } -#else - ppc_tlb_invalidate_all(env); -#endif -} - /*****************************************************************************/ /* Special registers manipulation */ -#if defined(TARGET_PPC64) -void ppc_store_asr(CPUPPCState *env, target_ulong value) -{ - if (env->asr != value) { - env->asr = value; - tlb_flush(env, 1); - } -} -#endif - -void ppc_store_sdr1(CPUPPCState *env, target_ulong value) -{ - LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value); - if (env->spr[SPR_SDR1] != value) { - env->spr[SPR_SDR1] = value; -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { - target_ulong htabsize = value & SDR_64_HTABSIZE; - - if (htabsize > 28) { - fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx - " stored in SDR1\n", htabsize); - htabsize = 28; - } - env->htab_mask = (1ULL << (htabsize + 18)) - 1; - env->htab_base = value & SDR_64_HTABORG; - } else -#endif /* defined(TARGET_PPC64) */ - { - /* FIXME: Should check for valid HTABMASK values */ - env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF; - env->htab_base = value & SDR_32_HTABORG; - } - tlb_flush(env, 1); - } -} - -#if defined(TARGET_PPC64) -target_ulong ppc_load_sr(CPUPPCState *env, int slb_nr) -{ - /* XXX */ - return 0; -} -#endif - -void ppc_store_sr(CPUPPCState *env, int srnum, target_ulong value) -{ - LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, - srnum, value, env->sr[srnum]); -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { - uint64_t rb = 0, rs = 0; - - /* ESID = srnum */ - rb |= ((uint32_t)srnum & 0xf) << 28; - /* Set the valid bit */ - rb |= 1 << 27; - /* Index = ESID */ - rb |= (uint32_t)srnum; - - /* VSID = VSID */ - rs |= (value & 0xfffffff) << 12; - /* flags = flags */ - rs |= ((value >> 27) & 0xf) << 8; - - ppc_store_slb(env, rb, rs); - } else -#endif - if (env->sr[srnum] != value) { - env->sr[srnum] = value; -/* Invalidating 256MB of virtual memory in 4kB pages is way longer than - flusing the whole TLB. */ -#if !defined(FLUSH_ALL_TLBS) && 0 - { - target_ulong page, end; - /* Invalidate 256 MB of virtual memory */ - page = (16 << 20) * srnum; - end = page + (16 << 20); - for (; page != end; page += TARGET_PAGE_SIZE) { - tlb_flush_page(env, page); - } - } -#else - tlb_flush(env, 1); -#endif - } -} -#endif /* !defined(CONFIG_USER_ONLY) */ /* GDBstub can read and write MSR... */ void ppc_store_msr(CPUPPCState *env, target_ulong value) diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index e79b8f284f..1f6745192f 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -18,8 +18,24 @@ */ #include "cpu.h" #include "helper.h" +#include "kvm.h" +#include "kvm_ppc.h" +//#define DEBUG_MMU +//#define DEBUG_BATS +//#define DEBUG_SLB //#define DEBUG_SOFTWARE_TLB +//#define DUMP_PAGE_TABLES +//#define DEBUG_SOFTWARE_TLB +//#define FLUSH_ALL_TLBS + +#ifdef DEBUG_MMU +# define LOG_MMU(...) qemu_log(__VA_ARGS__) +# define LOG_MMU_STATE(env) log_cpu_state((env), 0) +#else +# define LOG_MMU(...) do { } while (0) +# define LOG_MMU_STATE(...) do { } while (0) +#endif #ifdef DEBUG_SOFTWARE_TLB # define LOG_SWTLB(...) qemu_log(__VA_ARGS__) @@ -27,6 +43,2461 @@ # define LOG_SWTLB(...) do { } while (0) #endif +#ifdef DEBUG_BATS +# define LOG_BATS(...) qemu_log(__VA_ARGS__) +#else +# define LOG_BATS(...) do { } while (0) +#endif + +#ifdef DEBUG_SLB +# define LOG_SLB(...) qemu_log(__VA_ARGS__) +#else +# define LOG_SLB(...) do { } while (0) +#endif + +/*****************************************************************************/ +/* PowerPC MMU emulation */ +#if defined(CONFIG_USER_ONLY) +int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, + int mmu_idx) +{ + int exception, error_code; + + if (rw == 2) { + exception = POWERPC_EXCP_ISI; + error_code = 0x40000000; + } else { + exception = POWERPC_EXCP_DSI; + error_code = 0x40000000; + if (rw) { + error_code |= 0x02000000; + } + env->spr[SPR_DAR] = address; + env->spr[SPR_DSISR] = error_code; + } + env->exception_index = exception; + env->error_code = error_code; + + return 1; +} + +#else +/* Common routines used by software and hardware TLBs emulation */ +static inline int pte_is_valid(target_ulong pte0) +{ + return pte0 & 0x80000000 ? 1 : 0; +} + +static inline void pte_invalidate(target_ulong *pte0) +{ + *pte0 &= ~0x80000000; +} + +#if defined(TARGET_PPC64) +static inline int pte64_is_valid(target_ulong pte0) +{ + return pte0 & 0x0000000000000001ULL ? 1 : 0; +} + +static inline void pte64_invalidate(target_ulong *pte0) +{ + *pte0 &= ~0x0000000000000001ULL; +} +#endif + +#define PTE_PTEM_MASK 0x7FFFFFBF +#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B) +#if defined(TARGET_PPC64) +#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL +#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F) +#endif + +static inline int pp_check(int key, int pp, int nx) +{ + int access; + + /* Compute access rights */ + /* When pp is 3/7, the result is undefined. Set it to noaccess */ + access = 0; + if (key == 0) { + switch (pp) { + case 0x0: + case 0x1: + case 0x2: + access |= PAGE_WRITE; + /* No break here */ + case 0x3: + case 0x6: + access |= PAGE_READ; + break; + } + } else { + switch (pp) { + case 0x0: + case 0x6: + access = 0; + break; + case 0x1: + case 0x3: + access = PAGE_READ; + break; + case 0x2: + access = PAGE_READ | PAGE_WRITE; + break; + } + } + if (nx == 0) { + access |= PAGE_EXEC; + } + + return access; +} + +static inline int check_prot(int prot, int rw, int access_type) +{ + int ret; + + if (access_type == ACCESS_CODE) { + if (prot & PAGE_EXEC) { + ret = 0; + } else { + ret = -2; + } + } else if (rw) { + if (prot & PAGE_WRITE) { + ret = 0; + } else { + ret = -2; + } + } else { + if (prot & PAGE_READ) { + ret = 0; + } else { + ret = -2; + } + } + + return ret; +} + +static inline int pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0, + target_ulong pte1, int h, int rw, int type) +{ + target_ulong ptem, mmask; + int access, ret, pteh, ptev, pp; + + ret = -1; + /* Check validity and table match */ +#if defined(TARGET_PPC64) + if (is_64b) { + ptev = pte64_is_valid(pte0); + pteh = (pte0 >> 1) & 1; + } else +#endif + { + ptev = pte_is_valid(pte0); + pteh = (pte0 >> 6) & 1; + } + if (ptev && h == pteh) { + /* Check vsid & api */ +#if defined(TARGET_PPC64) + if (is_64b) { + ptem = pte0 & PTE64_PTEM_MASK; + mmask = PTE64_CHECK_MASK; + pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004); + ctx->nx = (pte1 >> 2) & 1; /* No execute bit */ + ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */ + } else +#endif + { + ptem = pte0 & PTE_PTEM_MASK; + mmask = PTE_CHECK_MASK; + pp = pte1 & 0x00000003; + } + if (ptem == ctx->ptem) { + if (ctx->raddr != (target_phys_addr_t)-1ULL) { + /* all matches should have equal RPN, WIMG & PP */ + if ((ctx->raddr & mmask) != (pte1 & mmask)) { + qemu_log("Bad RPN/WIMG/PP\n"); + return -3; + } + } + /* Compute access rights */ + access = pp_check(ctx->key, pp, ctx->nx); + /* Keep the matching PTE informations */ + ctx->raddr = pte1; + ctx->prot = access; + ret = check_prot(ctx->prot, rw, type); + if (ret == 0) { + /* Access granted */ + LOG_MMU("PTE access granted !\n"); + } else { + /* Access right violation */ + LOG_MMU("PTE access rejected\n"); + } + } + } + + return ret; +} + +static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0, + target_ulong pte1, int h, int rw, int type) +{ + return pte_check(ctx, 0, pte0, pte1, h, rw, type); +} + +#if defined(TARGET_PPC64) +static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0, + target_ulong pte1, int h, int rw, int type) +{ + return pte_check(ctx, 1, pte0, pte1, h, rw, type); +} +#endif + +static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, + int ret, int rw) +{ + int store = 0; + + /* Update page flags */ + if (!(*pte1p & 0x00000100)) { + /* Update accessed flag */ + *pte1p |= 0x00000100; + store = 1; + } + if (!(*pte1p & 0x00000080)) { + if (rw == 1 && ret == 0) { + /* Update changed flag */ + *pte1p |= 0x00000080; + store = 1; + } else { + /* Force page fault for first write access */ + ctx->prot &= ~PAGE_WRITE; + } + } + + return store; +} + +/* Software driven TLB helpers */ +static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr, + int way, int is_code) +{ + int nr; + + /* Select TLB num in a way from address */ + nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1); + /* Select TLB way */ + nr += env->tlb_per_way * way; + /* 6xx have separate TLBs for instructions and data */ + if (is_code && env->id_tlbs == 1) { + nr += env->nb_tlb; + } + + return nr; +} + +static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env) +{ + ppc6xx_tlb_t *tlb; + int nr, max; + + /* LOG_SWTLB("Invalidate all TLBs\n"); */ + /* Invalidate all defined software TLB */ + max = env->nb_tlb; + if (env->id_tlbs == 1) { + max *= 2; + } + for (nr = 0; nr < max; nr++) { + tlb = &env->tlb.tlb6[nr]; + pte_invalidate(&tlb->pte0); + } + tlb_flush(env, 1); +} + +static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env, + target_ulong eaddr, + int is_code, int match_epn) +{ +#if !defined(FLUSH_ALL_TLBS) + ppc6xx_tlb_t *tlb; + int way, nr; + + /* Invalidate ITLB + DTLB, all ways */ + for (way = 0; way < env->nb_ways; way++) { + nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code); + tlb = &env->tlb.tlb6[nr]; + if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) { + LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr, + env->nb_tlb, eaddr); + pte_invalidate(&tlb->pte0); + tlb_flush_page(env, tlb->EPN); + } + } +#else + /* XXX: PowerPC specification say this is valid as well */ + ppc6xx_tlb_invalidate_all(env); +#endif +} + +static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env, + target_ulong eaddr, int is_code) +{ + ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0); +} + +void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, int is_code, + target_ulong pte0, target_ulong pte1) +{ + ppc6xx_tlb_t *tlb; + int nr; + + nr = ppc6xx_tlb_getnum(env, EPN, way, is_code); + tlb = &env->tlb.tlb6[nr]; + LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx + " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1); + /* Invalidate any pending reference in QEMU for this virtual address */ + ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1); + tlb->pte0 = pte0; + tlb->pte1 = pte1; + tlb->EPN = EPN; + /* Store last way for LRU mechanism */ + env->last_way = way; +} + +static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int access_type) +{ + ppc6xx_tlb_t *tlb; + int nr, best, way; + int ret; + + best = -1; + ret = -1; /* No TLB found */ + for (way = 0; way < env->nb_ways; way++) { + nr = ppc6xx_tlb_getnum(env, eaddr, way, + access_type == ACCESS_CODE ? 1 : 0); + tlb = &env->tlb.tlb6[nr]; + /* This test "emulates" the PTE index match for hardware TLBs */ + if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) { + LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx + "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb, + pte_is_valid(tlb->pte0) ? "valid" : "inval", + tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr); + continue; + } + LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " " + TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb, + pte_is_valid(tlb->pte0) ? "valid" : "inval", + tlb->EPN, eaddr, tlb->pte1, + rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D'); + switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) { + case -3: + /* TLB inconsistency */ + return -1; + case -2: + /* Access violation */ + ret = -2; + best = nr; + break; + case -1: + default: + /* No match */ + break; + case 0: + /* access granted */ + /* XXX: we should go on looping to check all TLBs consistency + * but we can speed-up the whole thing as the + * result would be undefined if TLBs are not consistent. + */ + ret = 0; + best = nr; + goto done; + } + } + if (best != -1) { + done: + LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n", + ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret); + /* Update page flags */ + pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw); + } + + return ret; +} + +/* Perform BAT hit & translation */ +static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp, + int *validp, int *protp, target_ulong *BATu, + target_ulong *BATl) +{ + target_ulong bl; + int pp, valid, prot; + + bl = (*BATu & 0x00001FFC) << 15; + valid = 0; + prot = 0; + if (((msr_pr == 0) && (*BATu & 0x00000002)) || + ((msr_pr != 0) && (*BATu & 0x00000001))) { + valid = 1; + pp = *BATl & 0x00000003; + if (pp != 0) { + prot = PAGE_READ | PAGE_EXEC; + if (pp == 0x2) { + prot |= PAGE_WRITE; + } + } + } + *blp = bl; + *validp = valid; + *protp = prot; +} + +static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp, + int *validp, int *protp, + target_ulong *BATu, target_ulong *BATl) +{ + target_ulong bl; + int key, pp, valid, prot; + + bl = (*BATl & 0x0000003F) << 17; + LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n", + (uint8_t)(*BATl & 0x0000003F), bl, ~bl); + prot = 0; + valid = (*BATl >> 6) & 1; + if (valid) { + pp = *BATu & 0x00000003; + if (msr_pr == 0) { + key = (*BATu >> 3) & 1; + } else { + key = (*BATu >> 2) & 1; + } + prot = pp_check(key, pp, 0); + } + *blp = bl; + *validp = valid; + *protp = prot; +} + +static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong virtual, int rw, int type) +{ + target_ulong *BATlt, *BATut, *BATu, *BATl; + target_ulong BEPIl, BEPIu, bl; + int i, valid, prot; + int ret = -1; + + LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__, + type == ACCESS_CODE ? 'I' : 'D', virtual); + switch (type) { + case ACCESS_CODE: + BATlt = env->IBAT[1]; + BATut = env->IBAT[0]; + break; + default: + BATlt = env->DBAT[1]; + BATut = env->DBAT[0]; + break; + } + for (i = 0; i < env->nb_BATs; i++) { + BATu = &BATut[i]; + BATl = &BATlt[i]; + BEPIu = *BATu & 0xF0000000; + BEPIl = *BATu & 0x0FFE0000; + if (unlikely(env->mmu_model == POWERPC_MMU_601)) { + bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl); + } else { + bat_size_prot(env, &bl, &valid, &prot, BATu, BATl); + } + LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx + " BATl " TARGET_FMT_lx "\n", __func__, + type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl); + if ((virtual & 0xF0000000) == BEPIu && + ((virtual & 0x0FFE0000) & ~bl) == BEPIl) { + /* BAT matches */ + if (valid != 0) { + /* Get physical address */ + ctx->raddr = (*BATl & 0xF0000000) | + ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | + (virtual & 0x0001F000); + /* Compute access rights */ + ctx->prot = prot; + ret = check_prot(ctx->prot, rw, type); + if (ret == 0) { + LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n", + i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', + ctx->prot & PAGE_WRITE ? 'W' : '-'); + } + break; + } + } + } + if (ret < 0) { +#if defined(DEBUG_BATS) + if (qemu_log_enabled()) { + LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual); + for (i = 0; i < 4; i++) { + BATu = &BATut[i]; + BATl = &BATlt[i]; + BEPIu = *BATu & 0xF0000000; + BEPIl = *BATu & 0x0FFE0000; + bl = (*BATu & 0x00001FFC) << 15; + LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx + " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " " + TARGET_FMT_lx " " TARGET_FMT_lx "\n", + __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, + *BATu, *BATl, BEPIu, BEPIl, bl); + } + } +#endif + } + /* No hit */ + return ret; +} + +static inline target_phys_addr_t get_pteg_offset(CPUPPCState *env, + target_phys_addr_t hash, + int pte_size) +{ + return (hash * pte_size * 8) & env->htab_mask; +} + +/* PTE table lookup */ +static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, + int rw, int type, int target_page_bits) +{ + target_phys_addr_t pteg_off; + target_ulong pte0, pte1; + int i, good = -1; + int ret, r; + + ret = -1; /* No entry found */ + pteg_off = get_pteg_offset(env, ctx->hash[h], + is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32); + for (i = 0; i < 8; i++) { +#if defined(TARGET_PPC64) + if (is_64b) { + if (env->external_htab) { + pte0 = ldq_p(env->external_htab + pteg_off + (i * 16)); + pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8); + } else { + pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16)); + pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8); + } + + r = pte64_check(ctx, pte0, pte1, h, rw, type); + LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " + TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", + pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h, + (int)((pte0 >> 1) & 1), ctx->ptem); + } else +#endif + { + if (env->external_htab) { + pte0 = ldl_p(env->external_htab + pteg_off + (i * 8)); + pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4); + } else { + pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8)); + pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4); + } + r = pte32_check(ctx, pte0, pte1, h, rw, type); + LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " + TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", + pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h, + (int)((pte0 >> 6) & 1), ctx->ptem); + } + switch (r) { + case -3: + /* PTE inconsistency */ + return -1; + case -2: + /* Access violation */ + ret = -2; + good = i; + break; + case -1: + default: + /* No PTE match */ + break; + case 0: + /* access granted */ + /* XXX: we should go on looping to check all PTEs consistency + * but if we can speed-up the whole thing as the + * result would be undefined if PTEs are not consistent. + */ + ret = 0; + good = i; + goto done; + } + } + if (good != -1) { + done: + LOG_MMU("found PTE at addr " TARGET_FMT_lx " prot=%01x ret=%d\n", + ctx->raddr, ctx->prot, ret); + /* Update page flags */ + pte1 = ctx->raddr; + if (pte_update_flags(ctx, &pte1, ret, rw) == 1) { +#if defined(TARGET_PPC64) + if (is_64b) { + if (env->external_htab) { + stq_p(env->external_htab + pteg_off + (good * 16) + 8, + pte1); + } else { + stq_phys_notdirty(env->htab_base + pteg_off + + (good * 16) + 8, pte1); + } + } else +#endif + { + if (env->external_htab) { + stl_p(env->external_htab + pteg_off + (good * 8) + 4, + pte1); + } else { + stl_phys_notdirty(env->htab_base + pteg_off + + (good * 8) + 4, pte1); + } + } + } + } + + /* We have a TLB that saves 4K pages, so let's + * split a huge page to 4k chunks */ + if (target_page_bits != TARGET_PAGE_BITS) { + ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1)) + & TARGET_PAGE_MASK; + } + return ret; +} + +static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw, + int type, int target_page_bits) +{ +#if defined(TARGET_PPC64) + if (env->mmu_model & POWERPC_MMU_64) { + return find_pte2(env, ctx, 1, h, rw, type, target_page_bits); + } +#endif + + return find_pte2(env, ctx, 0, h, rw, type, target_page_bits); +} + +#if defined(TARGET_PPC64) +static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr) +{ + uint64_t esid_256M, esid_1T; + int n; + + LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr); + + esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V; + esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V; + + for (n = 0; n < env->slb_nr; n++) { + ppc_slb_t *slb = &env->slb[n]; + + LOG_SLB("%s: slot %d %016" PRIx64 " %016" + PRIx64 "\n", __func__, n, slb->esid, slb->vsid); + /* We check for 1T matches on all MMUs here - if the MMU + * doesn't have 1T segment support, we will have prevented 1T + * entries from being inserted in the slbmte code. */ + if (((slb->esid == esid_256M) && + ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M)) + || ((slb->esid == esid_1T) && + ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) { + return slb; + } + } + + return NULL; +} + +void ppc_slb_invalidate_all(CPUPPCState *env) +{ + int n, do_invalidate; + + do_invalidate = 0; + /* XXX: Warning: slbia never invalidates the first segment */ + for (n = 1; n < env->slb_nr; n++) { + ppc_slb_t *slb = &env->slb[n]; + + if (slb->esid & SLB_ESID_V) { + slb->esid &= ~SLB_ESID_V; + /* XXX: given the fact that segment size is 256 MB or 1TB, + * and we still don't have a tlb_flush_mask(env, n, mask) + * in QEMU, we just invalidate all TLBs + */ + do_invalidate = 1; + } + } + if (do_invalidate) { + tlb_flush(env, 1); + } +} + +void ppc_slb_invalidate_one(CPUPPCState *env, uint64_t T0) +{ + ppc_slb_t *slb; + + slb = slb_lookup(env, T0); + if (!slb) { + return; + } + + if (slb->esid & SLB_ESID_V) { + slb->esid &= ~SLB_ESID_V; + + /* XXX: given the fact that segment size is 256 MB or 1TB, + * and we still don't have a tlb_flush_mask(env, n, mask) + * in QEMU, we just invalidate all TLBs + */ + tlb_flush(env, 1); + } +} + +int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) +{ + int slot = rb & 0xfff; + ppc_slb_t *slb = &env->slb[slot]; + + if (rb & (0x1000 - env->slb_nr)) { + return -1; /* Reserved bits set or slot too high */ + } + if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) { + return -1; /* Bad segment size */ + } + if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) { + return -1; /* 1T segment on MMU that doesn't support it */ + } + + /* Mask out the slot number as we store the entry */ + slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V); + slb->vsid = rs; + + LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64 + " %016" PRIx64 "\n", __func__, slot, rb, rs, + slb->esid, slb->vsid); + + return 0; +} + +int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, target_ulong *rt) +{ + int slot = rb & 0xfff; + ppc_slb_t *slb = &env->slb[slot]; + + if (slot >= env->slb_nr) { + return -1; + } + + *rt = slb->esid; + return 0; +} + +int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb, target_ulong *rt) +{ + int slot = rb & 0xfff; + ppc_slb_t *slb = &env->slb[slot]; + + if (slot >= env->slb_nr) { + return -1; + } + + *rt = slb->vsid; + return 0; +} +#endif /* defined(TARGET_PPC64) */ + +/* Perform segment based translation */ +static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int type) +{ + target_phys_addr_t hash; + target_ulong vsid; + int ds, pr, target_page_bits; + int ret, ret2; + + pr = msr_pr; + ctx->eaddr = eaddr; +#if defined(TARGET_PPC64) + if (env->mmu_model & POWERPC_MMU_64) { + ppc_slb_t *slb; + target_ulong pageaddr; + int segment_bits; + + LOG_MMU("Check SLBs\n"); + slb = slb_lookup(env, eaddr); + if (!slb) { + return -5; + } + + if (slb->vsid & SLB_VSID_B) { + vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T; + segment_bits = 40; + } else { + vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT; + segment_bits = 28; + } + + target_page_bits = (slb->vsid & SLB_VSID_L) + ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS; + ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP) + : (slb->vsid & SLB_VSID_KS)); + ds = 0; + ctx->nx = !!(slb->vsid & SLB_VSID_N); + + pageaddr = eaddr & ((1ULL << segment_bits) + - (1ULL << target_page_bits)); + if (slb->vsid & SLB_VSID_B) { + hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits); + } else { + hash = vsid ^ (pageaddr >> target_page_bits); + } + /* Only 5 bits of the page index are used in the AVPN */ + ctx->ptem = (slb->vsid & SLB_VSID_PTEM) | + ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80)); + } else +#endif /* defined(TARGET_PPC64) */ + { + target_ulong sr, pgidx; + + sr = env->sr[eaddr >> 28]; + 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; + target_page_bits = TARGET_PAGE_BITS; + LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" + TARGET_FMT_lx " lr=" TARGET_FMT_lx + " ir=%d dr=%d pr=%d %d t=%d\n", + eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir, + (int)msr_dr, pr != 0 ? 1 : 0, rw, type); + pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits; + hash = vsid ^ pgidx; + ctx->ptem = (vsid << 7) | (pgidx >> 10); + } + LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n", + ctx->key, ds, ctx->nx, vsid); + ret = -1; + if (!ds) { + /* Check if instruction fetch is allowed, if needed */ + if (type != ACCESS_CODE || ctx->nx == 0) { + /* Page address translation */ + LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx + " hash " TARGET_FMT_plx "\n", + env->htab_base, env->htab_mask, hash); + ctx->hash[0] = hash; + ctx->hash[1] = ~hash; + + /* Initialize real address with an invalid value */ + ctx->raddr = (target_phys_addr_t)-1ULL; + if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx || + env->mmu_model == POWERPC_MMU_SOFT_74xx)) { + /* Software TLB search */ + ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); + } else { + LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx + " hash=" TARGET_FMT_plx "\n", + env->htab_base, env->htab_mask, vsid, ctx->ptem, + ctx->hash[0]); + /* Primary table lookup */ + ret = find_pte(env, ctx, 0, rw, type, target_page_bits); + if (ret < 0) { + /* Secondary table lookup */ + if (eaddr != 0xEFFFFFFF) { + LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx + " hash=" TARGET_FMT_plx "\n", env->htab_base, + env->htab_mask, vsid, ctx->ptem, ctx->hash[1]); + } + ret2 = find_pte(env, ctx, 1, rw, type, + target_page_bits); + if (ret2 != -1) { + ret = ret2; + } + } + } +#if defined(DUMP_PAGE_TABLES) + if (qemu_log_enabled()) { + target_phys_addr_t curaddr; + uint32_t a0, a1, a2, a3; + + qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx + "\n", sdr, mask + 0x80); + for (curaddr = sdr; curaddr < (sdr + mask + 0x80); + curaddr += 16) { + a0 = ldl_phys(curaddr); + a1 = ldl_phys(curaddr + 4); + a2 = ldl_phys(curaddr + 8); + a3 = ldl_phys(curaddr + 12); + if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) { + qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n", + curaddr, a0, a1, a2, a3); + } + } + } +#endif + } else { + LOG_MMU("No access allowed\n"); + ret = -3; + } + } else { + target_ulong sr; + + LOG_MMU("direct store...\n"); + /* Direct-store segment : absolutely *BUGGY* for now */ + + /* Direct-store implies a 32-bit MMU. + * Check the Segment Register's bus unit ID (BUID). + */ + sr = env->sr[eaddr >> 28]; + if ((sr & 0x1FF00000) >> 20 == 0x07f) { + /* Memory-forced I/O controller interface access */ + /* If T=1 and BUID=x'07F', the 601 performs a memory access + * to SR[28-31] LA[4-31], bypassing all protection mechanisms. + */ + ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF); + ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return 0; + } + + switch (type) { + case ACCESS_INT: + /* Integer load/store : only access allowed */ + break; + case ACCESS_CODE: + /* No code fetch is allowed in direct-store areas */ + return -4; + case ACCESS_FLOAT: + /* Floating point load/store */ + return -4; + case ACCESS_RES: + /* lwarx, ldarx or srwcx. */ + return -4; + case ACCESS_CACHE: + /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */ + /* Should make the instruction do no-op. + * As it already do no-op, it's quite easy :-) + */ + ctx->raddr = eaddr; + return 0; + case ACCESS_EXT: + /* eciwx or ecowx */ + return -4; + default: + qemu_log("ERROR: instruction should not need " + "address translation\n"); + return -4; + } + if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) { + ctx->raddr = eaddr; + ret = 2; + } else { + ret = -2; + } + } + + return ret; +} + +/* Generic TLB check function for embedded PowerPC implementations */ +int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb, + target_phys_addr_t *raddrp, + target_ulong address, uint32_t pid, int ext, + int i) +{ + target_ulong mask; + + /* Check valid flag */ + if (!(tlb->prot & PAGE_VALID)) { + return -1; + } + mask = ~(tlb->size - 1); + LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx + " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN, + mask, (uint32_t)tlb->PID, tlb->prot); + /* Check PID */ + if (tlb->PID != 0 && tlb->PID != pid) { + return -1; + } + /* Check effective address */ + if ((address & mask) != tlb->EPN) { + return -1; + } + *raddrp = (tlb->RPN & mask) | (address & ~mask); +#if (TARGET_PHYS_ADDR_BITS >= 36) + if (ext) { + /* Extend the physical address to 36 bits */ + *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32; + } +#endif + + return 0; +} + +/* Generic TLB search function for PowerPC embedded implementations */ +int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid) +{ + ppcemb_tlb_t *tlb; + target_phys_addr_t raddr; + int i, ret; + + /* Default return value is no match */ + ret = -1; + for (i = 0; i < env->nb_tlb; i++) { + tlb = &env->tlb.tlbe[i]; + if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) { + ret = i; + break; + } + } + + return ret; +} + +/* Helpers specific to PowerPC 40x implementations */ +static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env) +{ + ppcemb_tlb_t *tlb; + int i; + + for (i = 0; i < env->nb_tlb; i++) { + tlb = &env->tlb.tlbe[i]; + tlb->prot &= ~PAGE_VALID; + } + tlb_flush(env, 1); +} + +static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env, + target_ulong eaddr, uint32_t pid) +{ +#if !defined(FLUSH_ALL_TLBS) + ppcemb_tlb_t *tlb; + target_phys_addr_t raddr; + target_ulong page, end; + int i; + + for (i = 0; i < env->nb_tlb; i++) { + tlb = &env->tlb.tlbe[i]; + if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) { + end = tlb->EPN + tlb->size; + for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) { + tlb_flush_page(env, page); + } + tlb->prot &= ~PAGE_VALID; + break; + } + } +#else + ppc4xx_tlb_invalidate_all(env); +#endif +} + +static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong address, int rw, + int access_type) +{ + ppcemb_tlb_t *tlb; + target_phys_addr_t raddr; + int i, ret, zsel, zpr, pr; + + ret = -1; + raddr = (target_phys_addr_t)-1ULL; + pr = msr_pr; + for (i = 0; i < env->nb_tlb; i++) { + tlb = &env->tlb.tlbe[i]; + if (ppcemb_tlb_check(env, tlb, &raddr, address, + env->spr[SPR_40x_PID], 0, i) < 0) { + continue; + } + zsel = (tlb->attr >> 4) & 0xF; + zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3; + LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n", + __func__, i, zsel, zpr, rw, tlb->attr); + /* Check execute enable bit */ + switch (zpr) { + case 0x2: + if (pr != 0) { + goto check_perms; + } + /* No break here */ + case 0x3: + /* All accesses granted */ + ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + ret = 0; + break; + case 0x0: + if (pr != 0) { + /* Raise Zone protection fault. */ + env->spr[SPR_40x_ESR] = 1 << 22; + ctx->prot = 0; + ret = -2; + break; + } + /* No break here */ + case 0x1: + check_perms: + /* Check from TLB entry */ + ctx->prot = tlb->prot; + ret = check_prot(ctx->prot, rw, access_type); + if (ret == -2) { + env->spr[SPR_40x_ESR] = 0; + } + break; + } + if (ret >= 0) { + ctx->raddr = raddr; + LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx + " %d %d\n", __func__, address, ctx->raddr, ctx->prot, + ret); + return 0; + } + } + LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx + " %d %d\n", __func__, address, raddr, ctx->prot, ret); + + return ret; +} + +void store_40x_sler(CPUPPCState *env, uint32_t val) +{ + /* XXX: TO BE FIXED */ + if (val != 0x00000000) { + cpu_abort(env, "Little-endian regions are not supported by now\n"); + } + env->spr[SPR_405_SLER] = val; +} + +static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb, + target_phys_addr_t *raddr, int *prot, + target_ulong address, int rw, + int access_type, int i) +{ + int ret, prot2; + + if (ppcemb_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID], + !env->nb_pids, i) >= 0) { + goto found_tlb; + } + + if (env->spr[SPR_BOOKE_PID1] && + ppcemb_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID1], 0, i) >= 0) { + goto found_tlb; + } + + if (env->spr[SPR_BOOKE_PID2] && + ppcemb_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID2], 0, i) >= 0) { + goto found_tlb; + } + + LOG_SWTLB("%s: TLB entry not found\n", __func__); + return -1; + +found_tlb: + + if (msr_pr != 0) { + prot2 = tlb->prot & 0xF; + } else { + prot2 = (tlb->prot >> 4) & 0xF; + } + + /* Check the address space */ + if (access_type == ACCESS_CODE) { + if (msr_ir != (tlb->attr & 1)) { + LOG_SWTLB("%s: AS doesn't match\n", __func__); + return -1; + } + + *prot = prot2; + if (prot2 & PAGE_EXEC) { + LOG_SWTLB("%s: good TLB!\n", __func__); + return 0; + } + + LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2); + ret = -3; + } else { + if (msr_dr != (tlb->attr & 1)) { + LOG_SWTLB("%s: AS doesn't match\n", __func__); + return -1; + } + + *prot = prot2; + if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) { + LOG_SWTLB("%s: found TLB!\n", __func__); + return 0; + } + + LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2); + ret = -2; + } + + return ret; +} + +static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong address, int rw, + int access_type) +{ + ppcemb_tlb_t *tlb; + target_phys_addr_t raddr; + int i, ret; + + ret = -1; + raddr = (target_phys_addr_t)-1ULL; + for (i = 0; i < env->nb_tlb; i++) { + tlb = &env->tlb.tlbe[i]; + ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw, + access_type, i); + if (!ret) { + break; + } + } + + if (ret >= 0) { + ctx->raddr = raddr; + LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx + " %d %d\n", __func__, address, ctx->raddr, ctx->prot, + ret); + } else { + LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx + " %d %d\n", __func__, address, raddr, ctx->prot, ret); + } + + return ret; +} + +void booke206_flush_tlb(CPUPPCState *env, int flags, const int check_iprot) +{ + int tlb_size; + int i, j; + ppcmas_tlb_t *tlb = env->tlb.tlbm; + + for (i = 0; i < BOOKE206_MAX_TLBN; i++) { + if (flags & (1 << i)) { + tlb_size = booke206_tlb_size(env, i); + for (j = 0; j < tlb_size; j++) { + if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) { + tlb[j].mas1 &= ~MAS1_VALID; + } + } + } + tlb += booke206_tlb_size(env, i); + } + + tlb_flush(env, 1); +} + +target_phys_addr_t booke206_tlb_to_page_size(CPUPPCState *env, + ppcmas_tlb_t *tlb) +{ + int tlbm_size; + + tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; + + return 1024ULL << tlbm_size; +} + +/* TLB check function for MAS based SoftTLBs */ +int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, + target_phys_addr_t *raddrp, + target_ulong address, uint32_t pid) +{ + target_ulong mask; + uint32_t tlb_pid; + + /* Check valid flag */ + if (!(tlb->mas1 & MAS1_VALID)) { + return -1; + } + + mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); + LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%" + PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n", + __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3, + tlb->mas8); + + /* Check PID */ + tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT; + if (tlb_pid != 0 && tlb_pid != pid) { + return -1; + } + + /* Check effective address */ + if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) { + return -1; + } + + if (raddrp) { + *raddrp = (tlb->mas7_3 & mask) | (address & ~mask); + } + + return 0; +} + +static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb, + target_phys_addr_t *raddr, int *prot, + target_ulong address, int rw, + int access_type) +{ + int ret; + int prot2 = 0; + + if (ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID]) >= 0) { + goto found_tlb; + } + + if (env->spr[SPR_BOOKE_PID1] && + ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID1]) >= 0) { + goto found_tlb; + } + + if (env->spr[SPR_BOOKE_PID2] && + ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID2]) >= 0) { + goto found_tlb; + } + + LOG_SWTLB("%s: TLB entry not found\n", __func__); + return -1; + +found_tlb: + + if (msr_pr != 0) { + if (tlb->mas7_3 & MAS3_UR) { + prot2 |= PAGE_READ; + } + if (tlb->mas7_3 & MAS3_UW) { + prot2 |= PAGE_WRITE; + } + if (tlb->mas7_3 & MAS3_UX) { + prot2 |= PAGE_EXEC; + } + } else { + if (tlb->mas7_3 & MAS3_SR) { + prot2 |= PAGE_READ; + } + if (tlb->mas7_3 & MAS3_SW) { + prot2 |= PAGE_WRITE; + } + if (tlb->mas7_3 & MAS3_SX) { + prot2 |= PAGE_EXEC; + } + } + + /* Check the address space and permissions */ + if (access_type == ACCESS_CODE) { + if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { + LOG_SWTLB("%s: AS doesn't match\n", __func__); + return -1; + } + + *prot = prot2; + if (prot2 & PAGE_EXEC) { + LOG_SWTLB("%s: good TLB!\n", __func__); + return 0; + } + + LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2); + ret = -3; + } else { + if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { + LOG_SWTLB("%s: AS doesn't match\n", __func__); + return -1; + } + + *prot = prot2; + if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) { + LOG_SWTLB("%s: found TLB!\n", __func__); + return 0; + } + + LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2); + ret = -2; + } + + return ret; +} + +static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong address, int rw, + int access_type) +{ + ppcmas_tlb_t *tlb; + target_phys_addr_t raddr; + int i, j, ret; + + ret = -1; + raddr = (target_phys_addr_t)-1ULL; + + for (i = 0; i < BOOKE206_MAX_TLBN; i++) { + int ways = booke206_tlb_ways(env, i); + + for (j = 0; j < ways; j++) { + tlb = booke206_get_tlbm(env, i, address, j); + if (!tlb) { + continue; + } + ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address, + rw, access_type); + if (ret != -1) { + goto found_tlb; + } + } + } + +found_tlb: + + if (ret >= 0) { + ctx->raddr = raddr; + LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx + " %d %d\n", __func__, address, ctx->raddr, ctx->prot, + ret); + } else { + LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx + " %d %d\n", __func__, address, raddr, ctx->prot, ret); + } + + return ret; +} + +static const char *book3e_tsize_to_str[32] = { + "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K", + "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M", + "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G", + "1T", "2T" +}; + +static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf, + CPUPPCState *env) +{ + ppcemb_tlb_t *entry; + int i; + + if (kvm_enabled() && !env->kvm_sw_tlb) { + cpu_fprintf(f, "Cannot access KVM TLB\n"); + return; + } + + cpu_fprintf(f, "\nTLB:\n"); + cpu_fprintf(f, "Effective Physical Size PID Prot " + "Attr\n"); + + entry = &env->tlb.tlbe[0]; + for (i = 0; i < env->nb_tlb; i++, entry++) { + target_phys_addr_t ea, pa; + target_ulong mask; + uint64_t size = (uint64_t)entry->size; + char size_buf[20]; + + /* Check valid flag */ + if (!(entry->prot & PAGE_VALID)) { + continue; + } + + mask = ~(entry->size - 1); + ea = entry->EPN & mask; + pa = entry->RPN & mask; +#if (TARGET_PHYS_ADDR_BITS >= 36) + /* Extend the physical address to 36 bits */ + pa |= (target_phys_addr_t)(entry->RPN & 0xF) << 32; +#endif + size /= 1024; + if (size >= 1024) { + snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024); + } else { + snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size); + } + cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n", + (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID, + entry->prot, entry->attr); + } + +} + +static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf, + CPUPPCState *env, int tlbn, int offset, + int tlbsize) +{ + ppcmas_tlb_t *entry; + int i; + + cpu_fprintf(f, "\nTLB%d:\n", tlbn); + cpu_fprintf(f, "Effective Physical Size TID TS SRWX" + " URWX WIMGE U0123\n"); + + entry = &env->tlb.tlbm[offset]; + for (i = 0; i < tlbsize; i++, entry++) { + target_phys_addr_t ea, pa, size; + int tsize; + + if (!(entry->mas1 & MAS1_VALID)) { + continue; + } + + tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; + size = 1024ULL << tsize; + ea = entry->mas2 & ~(size - 1); + pa = entry->mas7_3 & ~(size - 1); + + cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c" + "U%c%c%c %c%c%c%c%c U%c%c%c%c\n", + (uint64_t)ea, (uint64_t)pa, + book3e_tsize_to_str[tsize], + (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT, + (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT, + entry->mas7_3 & MAS3_SR ? 'R' : '-', + entry->mas7_3 & MAS3_SW ? 'W' : '-', + entry->mas7_3 & MAS3_SX ? 'X' : '-', + entry->mas7_3 & MAS3_UR ? 'R' : '-', + entry->mas7_3 & MAS3_UW ? 'W' : '-', + entry->mas7_3 & MAS3_UX ? 'X' : '-', + entry->mas2 & MAS2_W ? 'W' : '-', + entry->mas2 & MAS2_I ? 'I' : '-', + entry->mas2 & MAS2_M ? 'M' : '-', + entry->mas2 & MAS2_G ? 'G' : '-', + entry->mas2 & MAS2_E ? 'E' : '-', + entry->mas7_3 & MAS3_U0 ? '0' : '-', + entry->mas7_3 & MAS3_U1 ? '1' : '-', + entry->mas7_3 & MAS3_U2 ? '2' : '-', + entry->mas7_3 & MAS3_U3 ? '3' : '-'); + } +} + +static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf, + CPUPPCState *env) +{ + int offset = 0; + int i; + + if (kvm_enabled() && !env->kvm_sw_tlb) { + cpu_fprintf(f, "Cannot access KVM TLB\n"); + return; + } + + for (i = 0; i < BOOKE206_MAX_TLBN; i++) { + int size = booke206_tlb_size(env, i); + + if (size == 0) { + continue; + } + + mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size); + offset += size; + } +} + +#if defined(TARGET_PPC64) +static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf, + CPUPPCState *env) +{ + int i; + uint64_t slbe, slbv; + + cpu_synchronize_state(env); + + cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n"); + for (i = 0; i < env->slb_nr; i++) { + slbe = env->slb[i].esid; + slbv = env->slb[i].vsid; + if (slbe == 0 && slbv == 0) { + continue; + } + cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n", + i, slbe, slbv); + } +} +#endif + +void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env) +{ + switch (env->mmu_model) { + case POWERPC_MMU_BOOKE: + mmubooke_dump_mmu(f, cpu_fprintf, env); + break; + case POWERPC_MMU_BOOKE206: + mmubooke206_dump_mmu(f, cpu_fprintf, env); + break; +#if defined(TARGET_PPC64) + case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: + mmubooks_dump_mmu(f, cpu_fprintf, env); + break; +#endif + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__); + } +} + +static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw) +{ + int in_plb, ret; + + ctx->raddr = eaddr; + ctx->prot = PAGE_READ | PAGE_EXEC; + ret = 0; + switch (env->mmu_model) { + case POWERPC_MMU_32B: + case POWERPC_MMU_601: + case POWERPC_MMU_SOFT_6xx: + case POWERPC_MMU_SOFT_74xx: + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_REAL: + case POWERPC_MMU_BOOKE: + ctx->prot |= PAGE_WRITE; + break; +#if defined(TARGET_PPC64) + case POWERPC_MMU_620: + case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: + /* Real address are 60 bits long */ + ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL; + ctx->prot |= PAGE_WRITE; + break; +#endif + case POWERPC_MMU_SOFT_4xx_Z: + if (unlikely(msr_pe != 0)) { + /* 403 family add some particular protections, + * using PBL/PBU registers for accesses with no translation. + */ + in_plb = + /* Check PLB validity */ + (env->pb[0] < env->pb[1] && + /* and address in plb area */ + eaddr >= env->pb[0] && eaddr < env->pb[1]) || + (env->pb[2] < env->pb[3] && + eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0; + if (in_plb ^ msr_px) { + /* Access in protected area */ + if (rw == 1) { + /* Access is not allowed */ + ret = -2; + } + } else { + /* Read-write access is allowed */ + ctx->prot |= PAGE_WRITE; + } + } + break; + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; + case POWERPC_MMU_BOOKE206: + cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n"); + break; + default: + cpu_abort(env, "Unknown or invalid MMU model\n"); + return -1; + } + + return ret; +} + +int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr, + int rw, int access_type) +{ + int ret; + +#if 0 + qemu_log("%s\n", __func__); +#endif + if ((access_type == ACCESS_CODE && msr_ir == 0) || + (access_type != ACCESS_CODE && msr_dr == 0)) { + if (env->mmu_model == POWERPC_MMU_BOOKE) { + /* The BookE MMU always performs address translation. The + IS and DS bits only affect the address space. */ + ret = mmubooke_get_physical_address(env, ctx, eaddr, + rw, access_type); + } else if (env->mmu_model == POWERPC_MMU_BOOKE206) { + ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, + access_type); + } else { + /* No address translation. */ + ret = check_physical(env, ctx, eaddr, rw); + } + } else { + ret = -1; + switch (env->mmu_model) { + case POWERPC_MMU_32B: + case POWERPC_MMU_601: + case POWERPC_MMU_SOFT_6xx: + case POWERPC_MMU_SOFT_74xx: + /* Try to find a BAT */ + if (env->nb_BATs != 0) { + ret = get_bat(env, ctx, eaddr, rw, access_type); + } +#if defined(TARGET_PPC64) + case POWERPC_MMU_620: + case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: +#endif + if (ret < 0) { + /* We didn't match any BAT entry or don't have BATs */ + ret = get_segment(env, ctx, eaddr, rw, access_type); + } + break; + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: + ret = mmu40x_get_physical_address(env, ctx, eaddr, + rw, access_type); + break; + case POWERPC_MMU_BOOKE: + ret = mmubooke_get_physical_address(env, ctx, eaddr, + rw, access_type); + break; + case POWERPC_MMU_BOOKE206: + ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, + access_type); + break; + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; + case POWERPC_MMU_REAL: + cpu_abort(env, "PowerPC in real mode do not do any translation\n"); + return -1; + default: + cpu_abort(env, "Unknown or invalid MMU model\n"); + return -1; + } + } +#if 0 + qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n", + __func__, eaddr, ret, ctx->raddr); +#endif + + return ret; +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr) +{ + mmu_ctx_t ctx; + + if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) { + return -1; + } + + return ctx.raddr & TARGET_PAGE_MASK; +} + +static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, + int rw) +{ + env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK; + env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK; + env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK; + env->spr[SPR_BOOKE_MAS3] = 0; + env->spr[SPR_BOOKE_MAS6] = 0; + env->spr[SPR_BOOKE_MAS7] = 0; + + /* AS */ + if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) { + env->spr[SPR_BOOKE_MAS1] |= MAS1_TS; + env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS; + } + + env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID; + env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK; + + switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) { + case MAS4_TIDSELD_PID0: + env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT; + break; + case MAS4_TIDSELD_PID1: + env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT; + break; + case MAS4_TIDSELD_PID2: + env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT; + break; + } + + env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16; + + /* next victim logic */ + env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT; + env->last_way++; + env->last_way &= booke206_tlb_ways(env, 0) - 1; + env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; +} + +/* Perform address translation */ +int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, + int mmu_idx) +{ + mmu_ctx_t ctx; + int access_type; + int ret = 0; + + if (rw == 2) { + /* code access */ + rw = 0; + access_type = ACCESS_CODE; + } else { + /* data access */ + access_type = env->access_type; + } + ret = get_physical_address(env, &ctx, address, rw, access_type); + if (ret == 0) { + tlb_set_page(env, address & TARGET_PAGE_MASK, + ctx.raddr & TARGET_PAGE_MASK, ctx.prot, + mmu_idx, TARGET_PAGE_SIZE); + ret = 0; + } else if (ret < 0) { + LOG_MMU_STATE(env); + if (access_type == ACCESS_CODE) { + switch (ret) { + case -1: + /* No matches in page tables or TLB */ + switch (env->mmu_model) { + case POWERPC_MMU_SOFT_6xx: + env->exception_index = POWERPC_EXCP_IFTLB; + env->error_code = 1 << 18; + env->spr[SPR_IMISS] = address; + env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem; + goto tlb_miss; + case POWERPC_MMU_SOFT_74xx: + env->exception_index = POWERPC_EXCP_IFTLB; + goto tlb_miss_74xx; + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: + env->exception_index = POWERPC_EXCP_ITLB; + env->error_code = 0; + env->spr[SPR_40x_DEAR] = address; + env->spr[SPR_40x_ESR] = 0x00000000; + break; + case POWERPC_MMU_32B: + case POWERPC_MMU_601: +#if defined(TARGET_PPC64) + case POWERPC_MMU_620: + case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: +#endif + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x40000000; + break; + case POWERPC_MMU_BOOKE206: + booke206_update_mas_tlb_miss(env, address, rw); + /* fall through */ + case POWERPC_MMU_BOOKE: + env->exception_index = POWERPC_EXCP_ITLB; + env->error_code = 0; + env->spr[SPR_BOOKE_DEAR] = address; + return -1; + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; + case POWERPC_MMU_REAL: + cpu_abort(env, "PowerPC in real mode should never raise " + "any MMU exceptions\n"); + return -1; + default: + cpu_abort(env, "Unknown or invalid MMU model\n"); + return -1; + } + break; + case -2: + /* Access rights violation */ + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x08000000; + break; + case -3: + /* No execute protection violation */ + if ((env->mmu_model == POWERPC_MMU_BOOKE) || + (env->mmu_model == POWERPC_MMU_BOOKE206)) { + env->spr[SPR_BOOKE_ESR] = 0x00000000; + } + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x10000000; + break; + case -4: + /* Direct store exception */ + /* No code fetch is allowed in direct-store areas */ + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x10000000; + break; +#if defined(TARGET_PPC64) + case -5: + /* No match in segment table */ + if (env->mmu_model == POWERPC_MMU_620) { + env->exception_index = POWERPC_EXCP_ISI; + /* XXX: this might be incorrect */ + env->error_code = 0x40000000; + } else { + env->exception_index = POWERPC_EXCP_ISEG; + env->error_code = 0; + } + break; +#endif + } + } else { + switch (ret) { + case -1: + /* No matches in page tables or TLB */ + switch (env->mmu_model) { + case POWERPC_MMU_SOFT_6xx: + if (rw == 1) { + env->exception_index = POWERPC_EXCP_DSTLB; + env->error_code = 1 << 16; + } else { + env->exception_index = POWERPC_EXCP_DLTLB; + env->error_code = 0; + } + env->spr[SPR_DMISS] = address; + env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem; + tlb_miss: + env->error_code |= ctx.key << 19; + env->spr[SPR_HASH1] = env->htab_base + + get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32); + env->spr[SPR_HASH2] = env->htab_base + + get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32); + break; + case POWERPC_MMU_SOFT_74xx: + if (rw == 1) { + env->exception_index = POWERPC_EXCP_DSTLB; + } else { + env->exception_index = POWERPC_EXCP_DLTLB; + } + tlb_miss_74xx: + /* Implement LRU algorithm */ + env->error_code = ctx.key << 19; + env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) | + ((env->last_way + 1) & (env->nb_ways - 1)); + env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem; + break; + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: + env->exception_index = POWERPC_EXCP_DTLB; + env->error_code = 0; + env->spr[SPR_40x_DEAR] = address; + if (rw) { + env->spr[SPR_40x_ESR] = 0x00800000; + } else { + env->spr[SPR_40x_ESR] = 0x00000000; + } + break; + case POWERPC_MMU_32B: + case POWERPC_MMU_601: +#if defined(TARGET_PPC64) + case POWERPC_MMU_620: + case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: +#endif + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = address; + if (rw == 1) { + env->spr[SPR_DSISR] = 0x42000000; + } else { + env->spr[SPR_DSISR] = 0x40000000; + } + break; + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; + case POWERPC_MMU_BOOKE206: + booke206_update_mas_tlb_miss(env, address, rw); + /* fall through */ + case POWERPC_MMU_BOOKE: + env->exception_index = POWERPC_EXCP_DTLB; + env->error_code = 0; + env->spr[SPR_BOOKE_DEAR] = address; + env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0; + return -1; + case POWERPC_MMU_REAL: + cpu_abort(env, "PowerPC in real mode should never raise " + "any MMU exceptions\n"); + return -1; + default: + cpu_abort(env, "Unknown or invalid MMU model\n"); + return -1; + } + break; + case -2: + /* Access rights violation */ + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + if (env->mmu_model == POWERPC_MMU_SOFT_4xx + || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) { + env->spr[SPR_40x_DEAR] = address; + if (rw) { + env->spr[SPR_40x_ESR] |= 0x00800000; + } + } else if ((env->mmu_model == POWERPC_MMU_BOOKE) || + (env->mmu_model == POWERPC_MMU_BOOKE206)) { + env->spr[SPR_BOOKE_DEAR] = address; + env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0; + } else { + env->spr[SPR_DAR] = address; + if (rw == 1) { + env->spr[SPR_DSISR] = 0x0A000000; + } else { + env->spr[SPR_DSISR] = 0x08000000; + } + } + break; + case -4: + /* Direct store exception */ + switch (access_type) { + case ACCESS_FLOAT: + /* Floating point load/store */ + env->exception_index = POWERPC_EXCP_ALIGN; + env->error_code = POWERPC_EXCP_ALIGN_FP; + env->spr[SPR_DAR] = address; + break; + case ACCESS_RES: + /* lwarx, ldarx or stwcx. */ + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = address; + if (rw == 1) { + env->spr[SPR_DSISR] = 0x06000000; + } else { + env->spr[SPR_DSISR] = 0x04000000; + } + break; + case ACCESS_EXT: + /* eciwx or ecowx */ + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = address; + if (rw == 1) { + env->spr[SPR_DSISR] = 0x06100000; + } else { + env->spr[SPR_DSISR] = 0x04100000; + } + break; + default: + printf("DSI: invalid exception (%d)\n", ret); + env->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = + POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL; + env->spr[SPR_DAR] = address; + break; + } + break; +#if defined(TARGET_PPC64) + case -5: + /* No match in segment table */ + if (env->mmu_model == POWERPC_MMU_620) { + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = address; + /* XXX: this might be incorrect */ + if (rw == 1) { + env->spr[SPR_DSISR] = 0x42000000; + } else { + env->spr[SPR_DSISR] = 0x40000000; + } + } else { + env->exception_index = POWERPC_EXCP_DSEG; + env->error_code = 0; + env->spr[SPR_DAR] = address; + } + break; +#endif + } + } +#if 0 + printf("%s: set exception to %d %02x\n", __func__, + env->exception, env->error_code); +#endif + ret = 1; + } + + return ret; +} + +/*****************************************************************************/ +/* BATs management */ +#if !defined(FLUSH_ALL_TLBS) +static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu, + target_ulong mask) +{ + target_ulong base, end, page; + + base = BATu & ~0x0001FFFF; + end = base + mask + 0x00020000; + LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " (" + TARGET_FMT_lx ")\n", base, end, mask); + for (page = base; page != end; page += TARGET_PAGE_SIZE) { + tlb_flush_page(env, page); + } + LOG_BATS("Flush done\n"); +} +#endif + +static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr, + target_ulong value) +{ + LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID, + nr, ul == 0 ? 'u' : 'l', value, env->nip); +} + +void ppc_store_ibatu(CPUPPCState *env, int nr, target_ulong value) +{ + target_ulong mask; + + dump_store_bat(env, 'I', 0, nr, value); + if (env->IBAT[0][nr] != value) { + mask = (value << 15) & 0x0FFE0000UL; +#if !defined(FLUSH_ALL_TLBS) + do_invalidate_BAT(env, env->IBAT[0][nr], mask); +#endif + /* When storing valid upper BAT, mask BEPI and BRPN + * and invalidate all TLBs covered by this BAT + */ + mask = (value << 15) & 0x0FFE0000UL; + env->IBAT[0][nr] = (value & 0x00001FFFUL) | + (value & ~0x0001FFFFUL & ~mask); + env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) | + (env->IBAT[1][nr] & ~0x0001FFFF & ~mask); +#if !defined(FLUSH_ALL_TLBS) + do_invalidate_BAT(env, env->IBAT[0][nr], mask); +#else + tlb_flush(env, 1); +#endif + } +} + +void ppc_store_ibatl(CPUPPCState *env, int nr, target_ulong value) +{ + dump_store_bat(env, 'I', 1, nr, value); + env->IBAT[1][nr] = value; +} + +void ppc_store_dbatu(CPUPPCState *env, int nr, target_ulong value) +{ + target_ulong mask; + + dump_store_bat(env, 'D', 0, nr, value); + if (env->DBAT[0][nr] != value) { + /* When storing valid upper BAT, mask BEPI and BRPN + * and invalidate all TLBs covered by this BAT + */ + mask = (value << 15) & 0x0FFE0000UL; +#if !defined(FLUSH_ALL_TLBS) + do_invalidate_BAT(env, env->DBAT[0][nr], mask); +#endif + mask = (value << 15) & 0x0FFE0000UL; + env->DBAT[0][nr] = (value & 0x00001FFFUL) | + (value & ~0x0001FFFFUL & ~mask); + env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) | + (env->DBAT[1][nr] & ~0x0001FFFF & ~mask); +#if !defined(FLUSH_ALL_TLBS) + do_invalidate_BAT(env, env->DBAT[0][nr], mask); +#else + tlb_flush(env, 1); +#endif + } +} + +void ppc_store_dbatl(CPUPPCState *env, int nr, target_ulong value) +{ + dump_store_bat(env, 'D', 1, nr, value); + env->DBAT[1][nr] = value; +} + +void ppc_store_ibatu_601(CPUPPCState *env, int nr, target_ulong value) +{ + target_ulong mask; +#if defined(FLUSH_ALL_TLBS) + int do_inval; +#endif + + dump_store_bat(env, 'I', 0, nr, value); + if (env->IBAT[0][nr] != value) { +#if defined(FLUSH_ALL_TLBS) + do_inval = 0; +#endif + mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL; + if (env->IBAT[1][nr] & 0x40) { + /* Invalidate BAT only if it is valid */ +#if !defined(FLUSH_ALL_TLBS) + do_invalidate_BAT(env, env->IBAT[0][nr], mask); +#else + do_inval = 1; +#endif + } + /* When storing valid upper BAT, mask BEPI and BRPN + * and invalidate all TLBs covered by this BAT + */ + env->IBAT[0][nr] = (value & 0x00001FFFUL) | + (value & ~0x0001FFFFUL & ~mask); + env->DBAT[0][nr] = env->IBAT[0][nr]; + if (env->IBAT[1][nr] & 0x40) { +#if !defined(FLUSH_ALL_TLBS) + do_invalidate_BAT(env, env->IBAT[0][nr], mask); +#else + do_inval = 1; +#endif + } +#if defined(FLUSH_ALL_TLBS) + if (do_inval) { + tlb_flush(env, 1); + } +#endif + } +} + +void ppc_store_ibatl_601(CPUPPCState *env, int nr, target_ulong value) +{ + target_ulong mask; +#if defined(FLUSH_ALL_TLBS) + int do_inval; +#endif + + dump_store_bat(env, 'I', 1, nr, value); + if (env->IBAT[1][nr] != value) { +#if defined(FLUSH_ALL_TLBS) + do_inval = 0; +#endif + if (env->IBAT[1][nr] & 0x40) { +#if !defined(FLUSH_ALL_TLBS) + mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL; + do_invalidate_BAT(env, env->IBAT[0][nr], mask); +#else + do_inval = 1; +#endif + } + if (value & 0x40) { +#if !defined(FLUSH_ALL_TLBS) + mask = (value << 17) & 0x0FFE0000UL; + do_invalidate_BAT(env, env->IBAT[0][nr], mask); +#else + do_inval = 1; +#endif + } + env->IBAT[1][nr] = value; + env->DBAT[1][nr] = value; +#if defined(FLUSH_ALL_TLBS) + if (do_inval) { + tlb_flush(env, 1); + } +#endif + } +} + +/*****************************************************************************/ +/* TLB management */ +void ppc_tlb_invalidate_all(CPUPPCState *env) +{ + switch (env->mmu_model) { + case POWERPC_MMU_SOFT_6xx: + case POWERPC_MMU_SOFT_74xx: + ppc6xx_tlb_invalidate_all(env); + break; + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: + ppc4xx_tlb_invalidate_all(env); + break; + case POWERPC_MMU_REAL: + cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n"); + break; + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; + case POWERPC_MMU_BOOKE: + tlb_flush(env, 1); + break; + case POWERPC_MMU_BOOKE206: + booke206_flush_tlb(env, -1, 0); + break; + case POWERPC_MMU_32B: + case POWERPC_MMU_601: +#if defined(TARGET_PPC64) + case POWERPC_MMU_620: + case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: +#endif /* defined(TARGET_PPC64) */ + tlb_flush(env, 1); + break; + default: + /* XXX: TODO */ + cpu_abort(env, "Unknown MMU model\n"); + break; + } +} + +void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) +{ +#if !defined(FLUSH_ALL_TLBS) + addr &= TARGET_PAGE_MASK; + switch (env->mmu_model) { + case POWERPC_MMU_SOFT_6xx: + case POWERPC_MMU_SOFT_74xx: + ppc6xx_tlb_invalidate_virt(env, addr, 0); + if (env->id_tlbs == 1) { + ppc6xx_tlb_invalidate_virt(env, addr, 1); + } + break; + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: + ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]); + break; + case POWERPC_MMU_REAL: + cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n"); + break; + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; + case POWERPC_MMU_BOOKE: + /* XXX: TODO */ + cpu_abort(env, "BookE MMU model is not implemented\n"); + break; + case POWERPC_MMU_BOOKE206: + /* XXX: TODO */ + cpu_abort(env, "BookE 2.06 MMU model is not implemented\n"); + break; + case POWERPC_MMU_32B: + case POWERPC_MMU_601: + /* tlbie invalidate TLBs for all segments */ + addr &= ~((target_ulong)-1ULL << 28); + /* XXX: this case should be optimized, + * giving a mask to tlb_flush_page + */ + tlb_flush_page(env, addr | (0x0 << 28)); + tlb_flush_page(env, addr | (0x1 << 28)); + tlb_flush_page(env, addr | (0x2 << 28)); + tlb_flush_page(env, addr | (0x3 << 28)); + tlb_flush_page(env, addr | (0x4 << 28)); + tlb_flush_page(env, addr | (0x5 << 28)); + tlb_flush_page(env, addr | (0x6 << 28)); + tlb_flush_page(env, addr | (0x7 << 28)); + tlb_flush_page(env, addr | (0x8 << 28)); + tlb_flush_page(env, addr | (0x9 << 28)); + tlb_flush_page(env, addr | (0xA << 28)); + tlb_flush_page(env, addr | (0xB << 28)); + tlb_flush_page(env, addr | (0xC << 28)); + tlb_flush_page(env, addr | (0xD << 28)); + tlb_flush_page(env, addr | (0xE << 28)); + tlb_flush_page(env, addr | (0xF << 28)); + break; +#if defined(TARGET_PPC64) + case POWERPC_MMU_620: + case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: + /* tlbie invalidate TLBs for all segments */ + /* XXX: given the fact that there are too many segments to invalidate, + * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU, + * we just invalidate all TLBs + */ + tlb_flush(env, 1); + break; +#endif /* defined(TARGET_PPC64) */ + default: + /* XXX: TODO */ + cpu_abort(env, "Unknown MMU model\n"); + break; + } +#else + ppc_tlb_invalidate_all(env); +#endif +} + +/*****************************************************************************/ +/* Special registers manipulation */ +#if defined(TARGET_PPC64) +void ppc_store_asr(CPUPPCState *env, target_ulong value) +{ + if (env->asr != value) { + env->asr = value; + tlb_flush(env, 1); + } +} +#endif + +void ppc_store_sdr1(CPUPPCState *env, target_ulong value) +{ + LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value); + if (env->spr[SPR_SDR1] != value) { + env->spr[SPR_SDR1] = value; +#if defined(TARGET_PPC64) + if (env->mmu_model & POWERPC_MMU_64) { + target_ulong htabsize = value & SDR_64_HTABSIZE; + + if (htabsize > 28) { + fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx + " stored in SDR1\n", htabsize); + htabsize = 28; + } + env->htab_mask = (1ULL << (htabsize + 18)) - 1; + env->htab_base = value & SDR_64_HTABORG; + } else +#endif /* defined(TARGET_PPC64) */ + { + /* FIXME: Should check for valid HTABMASK values */ + env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF; + env->htab_base = value & SDR_32_HTABORG; + } + tlb_flush(env, 1); + } +} + +#if defined(TARGET_PPC64) +target_ulong ppc_load_sr(CPUPPCState *env, int slb_nr) +{ + /* XXX */ + return 0; +} +#endif + +void ppc_store_sr(CPUPPCState *env, int srnum, target_ulong value) +{ + LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, + srnum, value, env->sr[srnum]); +#if defined(TARGET_PPC64) + if (env->mmu_model & POWERPC_MMU_64) { + uint64_t rb = 0, rs = 0; + + /* ESID = srnum */ + rb |= ((uint32_t)srnum & 0xf) << 28; + /* Set the valid bit */ + rb |= 1 << 27; + /* Index = ESID */ + rb |= (uint32_t)srnum; + + /* VSID = VSID */ + rs |= (value & 0xfffffff) << 12; + /* flags = flags */ + rs |= ((value >> 27) & 0xf) << 8; + + ppc_store_slb(env, rb, rs); + } else +#endif + if (env->sr[srnum] != value) { + env->sr[srnum] = value; +/* Invalidating 256MB of virtual memory in 4kB pages is way longer than + flusing the whole TLB. */ +#if !defined(FLUSH_ALL_TLBS) && 0 + { + target_ulong page, end; + /* Invalidate 256 MB of virtual memory */ + page = (16 << 20) * srnum; + end = page + (16 << 20); + for (; page != end; page += TARGET_PAGE_SIZE) { + tlb_flush_page(env, page); + } + } +#else + tlb_flush(env, 1); +#endif + } +} +#endif /* !defined(CONFIG_USER_ONLY) */ + /*****************************************************************************/ /* SPR accesses */ From 9aa5b15848b58a4879d2c4d971d102f22b6001a3 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:34 +0000 Subject: [PATCH 14/72] ppc: Cleanup MMU merge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove useless wrappers. In some cases 'int' parameters are changed to uint32_t. Make internal functions static. Signed-off-by: Blue Swirl [agraf: fix kvm compilation] Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 21 ------- target-ppc/mmu_helper.c | 120 ++++++++++++---------------------------- 2 files changed, 35 insertions(+), 106 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 32cfcefb07..9b157f0246 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1118,24 +1118,11 @@ void do_interrupt (CPUPPCState *env); void ppc_hw_interrupt (CPUPPCState *env); #if !defined(CONFIG_USER_ONLY) -void ppc6xx_tlb_store (CPUPPCState *env, target_ulong EPN, int way, int is_code, - target_ulong pte0, target_ulong pte1); -void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value); -void ppc_store_ibatl (CPUPPCState *env, int nr, target_ulong value); -void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value); -void ppc_store_dbatl (CPUPPCState *env, int nr, target_ulong value); -void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value); -void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value); void ppc_store_sdr1 (CPUPPCState *env, target_ulong value); #if defined(TARGET_PPC64) void ppc_store_asr (CPUPPCState *env, target_ulong value); -target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr); -target_ulong ppc_load_sr (CPUPPCState *env, int sr_nr); int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs); -int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt); -int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt); #endif /* defined(TARGET_PPC64) */ -void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value); #endif /* !defined(CONFIG_USER_ONLY) */ void ppc_store_msr (CPUPPCState *env, target_ulong value); @@ -1174,19 +1161,11 @@ void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); void booke206_flush_tlb(CPUPPCState *env, int flags, const int check_iprot); target_phys_addr_t booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb); -int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb, - target_phys_addr_t *raddrp, target_ulong address, - uint32_t pid, int ext, int i); int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, target_phys_addr_t *raddrp, target_ulong address, uint32_t pid); void ppc_tlb_invalidate_all (CPUPPCState *env); void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr); -#if defined(TARGET_PPC64) -void ppc_slb_invalidate_all (CPUPPCState *env); -void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0); -#endif -int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid); #endif #endif diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 1f6745192f..d65d2909b4 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -347,8 +347,8 @@ static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env, ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0); } -void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, int is_code, - target_ulong pte0, target_ulong pte1) +static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, + int is_code, target_ulong pte0, target_ulong pte1) { ppc6xx_tlb_t *tlb; int nr; @@ -712,7 +712,10 @@ static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr) return NULL; } -void ppc_slb_invalidate_all(CPUPPCState *env) +/*****************************************************************************/ +/* SPR accesses */ + +void helper_slbia(CPUPPCState *env) { int n, do_invalidate; @@ -735,11 +738,11 @@ void ppc_slb_invalidate_all(CPUPPCState *env) } } -void ppc_slb_invalidate_one(CPUPPCState *env, uint64_t T0) +void helper_slbie(CPUPPCState *env, target_ulong addr) { ppc_slb_t *slb; - slb = slb_lookup(env, T0); + slb = slb_lookup(env, addr); if (!slb) { return; } @@ -781,7 +784,8 @@ int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) return 0; } -int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, target_ulong *rt) +static int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, + target_ulong *rt) { int slot = rb & 0xfff; ppc_slb_t *slb = &env->slb[slot]; @@ -794,7 +798,8 @@ int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, target_ulong *rt) return 0; } -int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb, target_ulong *rt) +static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb, + target_ulong *rt) { int slot = rb & 0xfff; ppc_slb_t *slb = &env->slb[slot]; @@ -1003,10 +1008,10 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx, } /* Generic TLB check function for embedded PowerPC implementations */ -int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb, - target_phys_addr_t *raddrp, - target_ulong address, uint32_t pid, int ext, - int i) +static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb, + target_phys_addr_t *raddrp, + target_ulong address, uint32_t pid, int ext, + int i) { target_ulong mask; @@ -1038,7 +1043,8 @@ int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb, } /* Generic TLB search function for PowerPC embedded implementations */ -int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid) +static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, + uint32_t pid) { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; @@ -2144,7 +2150,7 @@ static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr, nr, ul == 0 ? 'u' : 'l', value, env->nip); } -void ppc_store_ibatu(CPUPPCState *env, int nr, target_ulong value) +void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value) { target_ulong mask; @@ -2170,13 +2176,13 @@ void ppc_store_ibatu(CPUPPCState *env, int nr, target_ulong value) } } -void ppc_store_ibatl(CPUPPCState *env, int nr, target_ulong value) +void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value) { dump_store_bat(env, 'I', 1, nr, value); env->IBAT[1][nr] = value; } -void ppc_store_dbatu(CPUPPCState *env, int nr, target_ulong value) +void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value) { target_ulong mask; @@ -2202,13 +2208,13 @@ void ppc_store_dbatu(CPUPPCState *env, int nr, target_ulong value) } } -void ppc_store_dbatl(CPUPPCState *env, int nr, target_ulong value) +void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value) { dump_store_bat(env, 'D', 1, nr, value); env->DBAT[1][nr] = value; } -void ppc_store_ibatu_601(CPUPPCState *env, int nr, target_ulong value) +void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value) { target_ulong mask; #if defined(FLUSH_ALL_TLBS) @@ -2250,7 +2256,7 @@ void ppc_store_ibatu_601(CPUPPCState *env, int nr, target_ulong value) } } -void ppc_store_ibatl_601(CPUPPCState *env, int nr, target_ulong value) +void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value) { target_ulong mask; #if defined(FLUSH_ALL_TLBS) @@ -2446,18 +2452,22 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value) } } -#if defined(TARGET_PPC64) -target_ulong ppc_load_sr(CPUPPCState *env, int slb_nr) +/* Segment registers load and store */ +target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num) { - /* XXX */ - return 0; -} +#if defined(TARGET_PPC64) + if (env->mmu_model & POWERPC_MMU_64) { + /* XXX */ + return 0; + } #endif + return env->sr[sr_num]; +} -void ppc_store_sr(CPUPPCState *env, int srnum, target_ulong value) +void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value) { LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, - srnum, value, env->sr[srnum]); + (int)srnum, value, env->sr[srnum]); #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { uint64_t rb = 0, rs = 0; @@ -2498,56 +2508,7 @@ void ppc_store_sr(CPUPPCState *env, int srnum, target_ulong value) } #endif /* !defined(CONFIG_USER_ONLY) */ -/*****************************************************************************/ -/* SPR accesses */ - #if !defined(CONFIG_USER_ONLY) -void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong val) -{ - ppc_store_ibatu(env, nr, val); -} - -void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong val) -{ - ppc_store_ibatl(env, nr, val); -} - -void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong val) -{ - ppc_store_dbatu(env, nr, val); -} - -void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong val) -{ - ppc_store_dbatl(env, nr, val); -} - -void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong val) -{ - ppc_store_ibatl_601(env, nr, val); -} - -void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong val) -{ - ppc_store_ibatu_601(env, nr, val); -} - -/* Segment registers load and store */ -target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num) -{ -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { - return ppc_load_sr(env, sr_num); - } -#endif - return env->sr[sr_num]; -} - -void helper_store_sr(CPUPPCState *env, target_ulong sr_num, target_ulong val) -{ - ppc_store_sr(env, sr_num, val); -} - /* SLB management */ #if defined(TARGET_PPC64) void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) @@ -2579,17 +2540,6 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb) } return rt; } - -void helper_slbia(CPUPPCState *env) -{ - ppc_slb_invalidate_all(env); -} - -void helper_slbie(CPUPPCState *env, target_ulong addr) -{ - ppc_slb_invalidate_one(env, addr); -} - #endif /* defined(TARGET_PPC64) */ /* TLB management */ From 6de673d40660abc43605789fa2010f20abc5a7a4 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:35 +0000 Subject: [PATCH 15/72] ppc: Split off timebase helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move decrementer and timebase helpers to a dedicated file. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 2 + target-ppc/op_helper.c | 135 ----------------------------- target-ppc/timebase_helper.c | 160 +++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 135 deletions(-) create mode 100644 target-ppc/timebase_helper.c diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 71e25b14e1..19dc744f43 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -6,5 +6,7 @@ obj-y += excp_helper.o obj-y += fpu_helper.o obj-y += int_helper.o obj-y += mmu_helper.o +obj-y += timebase_helper.o +$(obj)/timebase_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index c854c71225..09299068fc 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -43,44 +43,6 @@ void helper_store_dump_spr(uint32_t sprn) qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn, env->spr[sprn]); } - -target_ulong helper_load_tbl(void) -{ - return (target_ulong)cpu_ppc_load_tbl(env); -} - -target_ulong helper_load_tbu(void) -{ - return cpu_ppc_load_tbu(env); -} - -target_ulong helper_load_atbl(void) -{ - return (target_ulong)cpu_ppc_load_atbl(env); -} - -target_ulong helper_load_atbu(void) -{ - return cpu_ppc_load_atbu(env); -} - -#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) -target_ulong helper_load_purr(void) -{ - return (target_ulong)cpu_ppc_load_purr(env); -} -#endif - -target_ulong helper_load_601_rtcl(void) -{ - return cpu_ppc601_load_rtcl(env); -} - -target_ulong helper_load_601_rtcu(void) -{ - return cpu_ppc601_load_rtcu(env); -} - #if !defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) void helper_store_asr(target_ulong val) @@ -94,46 +56,6 @@ void helper_store_sdr1(target_ulong val) ppc_store_sdr1(env, val); } -void helper_store_tbl(target_ulong val) -{ - cpu_ppc_store_tbl(env, val); -} - -void helper_store_tbu(target_ulong val) -{ - cpu_ppc_store_tbu(env, val); -} - -void helper_store_atbl(target_ulong val) -{ - cpu_ppc_store_atbl(env, val); -} - -void helper_store_atbu(target_ulong val) -{ - cpu_ppc_store_atbu(env, val); -} - -void helper_store_601_rtcl(target_ulong val) -{ - cpu_ppc601_store_rtcl(env, val); -} - -void helper_store_601_rtcu(target_ulong val) -{ - cpu_ppc601_store_rtcu(env, val); -} - -target_ulong helper_load_decr(void) -{ - return cpu_ppc_load_decr(env); -} - -void helper_store_decr(target_ulong val) -{ - cpu_ppc_store_decr(env, val); -} - void helper_store_hid0_601(target_ulong val) { target_ulong hid0; @@ -160,16 +82,6 @@ void helper_store_403_pbr(uint32_t num, target_ulong value) } } -target_ulong helper_load_40x_pit(void) -{ - return load_40x_pit(env); -} - -void helper_store_40x_pit(target_ulong val) -{ - store_40x_pit(env, val); -} - void helper_store_40x_dbcr0(target_ulong val) { store_40x_dbcr0(env, val); @@ -179,16 +91,6 @@ void helper_store_40x_sler(target_ulong val) { store_40x_sler(env, val); } - -void helper_store_booke_tcr(target_ulong val) -{ - store_booke_tcr(env, val); -} - -void helper_store_booke_tsr(target_ulong val) -{ - store_booke_tsr(env, val); -} #endif /*****************************************************************************/ @@ -380,43 +282,6 @@ target_ulong helper_clcs(uint32_t arg) } } -/*****************************************************************************/ -/* Embedded PowerPC specific helpers */ - -/* XXX: to be improved to check access rights when in user-mode */ -target_ulong helper_load_dcr(target_ulong dcrn) -{ - uint32_t val = 0; - - if (unlikely(env->dcr_env == NULL)) { - qemu_log("No DCR environment\n"); - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | - POWERPC_EXCP_INVAL_INVAL); - } else if (unlikely(ppc_dcr_read(env->dcr_env, - (uint32_t)dcrn, &val) != 0)) { - qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn); - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG); - } - return val; -} - -void helper_store_dcr(target_ulong dcrn, target_ulong val) -{ - if (unlikely(env->dcr_env == NULL)) { - qemu_log("No DCR environment\n"); - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | - POWERPC_EXCP_INVAL_INVAL); - } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, - (uint32_t)val) != 0)) { - qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn); - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG); - } -} - /*****************************************************************************/ /* Altivec extension helpers */ #if defined(HOST_WORDS_BIGENDIAN) diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c new file mode 100644 index 0000000000..23f5cfa3da --- /dev/null +++ b/target-ppc/timebase_helper.c @@ -0,0 +1,160 @@ +/* + * PowerPC emulation 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, see . + */ +#include "cpu.h" +#include "dyngen-exec.h" +#include "helper.h" + +/*****************************************************************************/ +/* SPR accesses */ + +target_ulong helper_load_tbl(void) +{ + return (target_ulong)cpu_ppc_load_tbl(env); +} + +target_ulong helper_load_tbu(void) +{ + return cpu_ppc_load_tbu(env); +} + +target_ulong helper_load_atbl(void) +{ + return (target_ulong)cpu_ppc_load_atbl(env); +} + +target_ulong helper_load_atbu(void) +{ + return cpu_ppc_load_atbu(env); +} + +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) +target_ulong helper_load_purr(void) +{ + return (target_ulong)cpu_ppc_load_purr(env); +} +#endif + +target_ulong helper_load_601_rtcl(void) +{ + return cpu_ppc601_load_rtcl(env); +} + +target_ulong helper_load_601_rtcu(void) +{ + return cpu_ppc601_load_rtcu(env); +} + +#if !defined(CONFIG_USER_ONLY) +void helper_store_tbl(target_ulong val) +{ + cpu_ppc_store_tbl(env, val); +} + +void helper_store_tbu(target_ulong val) +{ + cpu_ppc_store_tbu(env, val); +} + +void helper_store_atbl(target_ulong val) +{ + cpu_ppc_store_atbl(env, val); +} + +void helper_store_atbu(target_ulong val) +{ + cpu_ppc_store_atbu(env, val); +} + +void helper_store_601_rtcl(target_ulong val) +{ + cpu_ppc601_store_rtcl(env, val); +} + +void helper_store_601_rtcu(target_ulong val) +{ + cpu_ppc601_store_rtcu(env, val); +} + +target_ulong helper_load_decr(void) +{ + return cpu_ppc_load_decr(env); +} + +void helper_store_decr(target_ulong val) +{ + cpu_ppc_store_decr(env, val); +} + +target_ulong helper_load_40x_pit(void) +{ + return load_40x_pit(env); +} + +void helper_store_40x_pit(target_ulong val) +{ + store_40x_pit(env, val); +} + +void helper_store_booke_tcr(target_ulong val) +{ + store_booke_tcr(env, val); +} + +void helper_store_booke_tsr(target_ulong val) +{ + store_booke_tsr(env, val); +} +#endif + +/*****************************************************************************/ +/* Embedded PowerPC specific helpers */ + +/* XXX: to be improved to check access rights when in user-mode */ +target_ulong helper_load_dcr(target_ulong dcrn) +{ + uint32_t val = 0; + + if (unlikely(env->dcr_env == NULL)) { + qemu_log("No DCR environment\n"); + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL); + } else if (unlikely(ppc_dcr_read(env->dcr_env, + (uint32_t)dcrn, &val) != 0)) { + qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn); + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG); + } + return val; +} + +void helper_store_dcr(target_ulong dcrn, target_ulong val) +{ + if (unlikely(env->dcr_env == NULL)) { + qemu_log("No DCR environment\n"); + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_INVAL); + } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, + (uint32_t)val) != 0)) { + qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn); + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG); + } +} From d0f1562d6ace0fdb7d2db190dd5a9a2e7492c3b3 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:36 +0000 Subject: [PATCH 16/72] ppc: Avoid AREG0 for timebase helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an explicit CPUPPCState parameter instead of relying on AREG0. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 1 - target-ppc/helper.h | 42 +++++++++++++++++------------------ target-ppc/timebase_helper.c | 43 ++++++++++++++++++------------------ target-ppc/translate.c | 16 +++++++++----- target-ppc/translate_init.c | 38 +++++++++++++++---------------- 5 files changed, 71 insertions(+), 69 deletions(-) diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 19dc744f43..4a8864115d 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -8,5 +8,4 @@ obj-y += int_helper.o obj-y += mmu_helper.o obj-y += timebase_helper.o -$(obj)/timebase_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index b1f7ba5bcb..81fc40eb1a 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -372,39 +372,39 @@ DEF_HELPER_3(divo, tl, env, tl, tl) DEF_HELPER_3(divs, tl, env, tl, tl) DEF_HELPER_3(divso, tl, env, tl, tl) -DEF_HELPER_1(load_dcr, tl, tl); -DEF_HELPER_2(store_dcr, void, tl, tl) +DEF_HELPER_2(load_dcr, tl, env, tl); +DEF_HELPER_3(store_dcr, void, env, tl, tl) DEF_HELPER_1(load_dump_spr, void, i32) DEF_HELPER_1(store_dump_spr, void, i32) -DEF_HELPER_0(load_tbl, tl) -DEF_HELPER_0(load_tbu, tl) -DEF_HELPER_0(load_atbl, tl) -DEF_HELPER_0(load_atbu, tl) -DEF_HELPER_0(load_601_rtcl, tl) -DEF_HELPER_0(load_601_rtcu, tl) +DEF_HELPER_1(load_tbl, tl, env) +DEF_HELPER_1(load_tbu, tl, env) +DEF_HELPER_1(load_atbl, tl, env) +DEF_HELPER_1(load_atbu, tl, env) +DEF_HELPER_1(load_601_rtcl, tl, env) +DEF_HELPER_1(load_601_rtcu, tl, env) #if !defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) DEF_HELPER_1(store_asr, void, tl) -DEF_HELPER_0(load_purr, tl) +DEF_HELPER_1(load_purr, tl, env) #endif DEF_HELPER_1(store_sdr1, void, tl) -DEF_HELPER_1(store_tbl, void, tl) -DEF_HELPER_1(store_tbu, void, tl) -DEF_HELPER_1(store_atbl, void, tl) -DEF_HELPER_1(store_atbu, void, tl) -DEF_HELPER_1(store_601_rtcl, void, tl) -DEF_HELPER_1(store_601_rtcu, void, tl) -DEF_HELPER_0(load_decr, tl) -DEF_HELPER_1(store_decr, void, tl) +DEF_HELPER_2(store_tbl, void, env, tl) +DEF_HELPER_2(store_tbu, void, env, tl) +DEF_HELPER_2(store_atbl, void, env, tl) +DEF_HELPER_2(store_atbu, void, env, tl) +DEF_HELPER_2(store_601_rtcl, void, env, tl) +DEF_HELPER_2(store_601_rtcu, void, env, tl) +DEF_HELPER_1(load_decr, tl, env) +DEF_HELPER_2(store_decr, void, env, tl) DEF_HELPER_1(store_hid0_601, void, tl) DEF_HELPER_2(store_403_pbr, void, i32, tl) -DEF_HELPER_0(load_40x_pit, tl) -DEF_HELPER_1(store_40x_pit, void, tl) +DEF_HELPER_1(load_40x_pit, tl, env) +DEF_HELPER_2(store_40x_pit, void, env, tl) DEF_HELPER_1(store_40x_dbcr0, void, tl) DEF_HELPER_1(store_40x_sler, void, tl) -DEF_HELPER_1(store_booke_tcr, void, tl) -DEF_HELPER_1(store_booke_tsr, void, tl) +DEF_HELPER_2(store_booke_tcr, void, env, tl) +DEF_HELPER_2(store_booke_tsr, void, env, tl) DEF_HELPER_3(store_ibatl, void, env, i32, tl) DEF_HELPER_3(store_ibatu, void, env, i32, tl) DEF_HELPER_3(store_dbatl, void, env, i32, tl) diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c index 23f5cfa3da..fad738a4af 100644 --- a/target-ppc/timebase_helper.c +++ b/target-ppc/timebase_helper.c @@ -17,106 +17,105 @@ * License along with this library; if not, see . */ #include "cpu.h" -#include "dyngen-exec.h" #include "helper.h" /*****************************************************************************/ /* SPR accesses */ -target_ulong helper_load_tbl(void) +target_ulong helper_load_tbl(CPUPPCState *env) { return (target_ulong)cpu_ppc_load_tbl(env); } -target_ulong helper_load_tbu(void) +target_ulong helper_load_tbu(CPUPPCState *env) { return cpu_ppc_load_tbu(env); } -target_ulong helper_load_atbl(void) +target_ulong helper_load_atbl(CPUPPCState *env) { return (target_ulong)cpu_ppc_load_atbl(env); } -target_ulong helper_load_atbu(void) +target_ulong helper_load_atbu(CPUPPCState *env) { return cpu_ppc_load_atbu(env); } #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) -target_ulong helper_load_purr(void) +target_ulong helper_load_purr(CPUPPCState *env) { return (target_ulong)cpu_ppc_load_purr(env); } #endif -target_ulong helper_load_601_rtcl(void) +target_ulong helper_load_601_rtcl(CPUPPCState *env) { return cpu_ppc601_load_rtcl(env); } -target_ulong helper_load_601_rtcu(void) +target_ulong helper_load_601_rtcu(CPUPPCState *env) { return cpu_ppc601_load_rtcu(env); } #if !defined(CONFIG_USER_ONLY) -void helper_store_tbl(target_ulong val) +void helper_store_tbl(CPUPPCState *env, target_ulong val) { cpu_ppc_store_tbl(env, val); } -void helper_store_tbu(target_ulong val) +void helper_store_tbu(CPUPPCState *env, target_ulong val) { cpu_ppc_store_tbu(env, val); } -void helper_store_atbl(target_ulong val) +void helper_store_atbl(CPUPPCState *env, target_ulong val) { cpu_ppc_store_atbl(env, val); } -void helper_store_atbu(target_ulong val) +void helper_store_atbu(CPUPPCState *env, target_ulong val) { cpu_ppc_store_atbu(env, val); } -void helper_store_601_rtcl(target_ulong val) +void helper_store_601_rtcl(CPUPPCState *env, target_ulong val) { cpu_ppc601_store_rtcl(env, val); } -void helper_store_601_rtcu(target_ulong val) +void helper_store_601_rtcu(CPUPPCState *env, target_ulong val) { cpu_ppc601_store_rtcu(env, val); } -target_ulong helper_load_decr(void) +target_ulong helper_load_decr(CPUPPCState *env) { return cpu_ppc_load_decr(env); } -void helper_store_decr(target_ulong val) +void helper_store_decr(CPUPPCState *env, target_ulong val) { cpu_ppc_store_decr(env, val); } -target_ulong helper_load_40x_pit(void) +target_ulong helper_load_40x_pit(CPUPPCState *env) { return load_40x_pit(env); } -void helper_store_40x_pit(target_ulong val) +void helper_store_40x_pit(CPUPPCState *env, target_ulong val) { store_40x_pit(env, val); } -void helper_store_booke_tcr(target_ulong val) +void helper_store_booke_tcr(CPUPPCState *env, target_ulong val) { store_booke_tcr(env, val); } -void helper_store_booke_tsr(target_ulong val) +void helper_store_booke_tsr(CPUPPCState *env, target_ulong val) { store_booke_tsr(env, val); } @@ -126,7 +125,7 @@ void helper_store_booke_tsr(target_ulong val) /* Embedded PowerPC specific helpers */ /* XXX: to be improved to check access rights when in user-mode */ -target_ulong helper_load_dcr(target_ulong dcrn) +target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn) { uint32_t val = 0; @@ -144,7 +143,7 @@ target_ulong helper_load_dcr(target_ulong dcrn) return val; } -void helper_store_dcr(target_ulong dcrn, target_ulong val) +void helper_store_dcr(CPUPPCState *env, target_ulong dcrn, target_ulong val) { if (unlikely(env->dcr_env == NULL)) { qemu_log("No DCR environment\n"); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 446f97e065..5eec4b040b 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -5717,7 +5717,7 @@ static void gen_mfdcr(DisasContext *ctx) /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); dcrn = tcg_const_tl(SPR(ctx->opcode)); - gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], dcrn); + gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, dcrn); tcg_temp_free(dcrn); #endif } @@ -5736,7 +5736,7 @@ static void gen_mtdcr(DisasContext *ctx) /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); dcrn = tcg_const_tl(SPR(ctx->opcode)); - gen_helper_store_dcr(dcrn, cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_dcr(cpu_env, dcrn, cpu_gpr[rS(ctx->opcode)]); tcg_temp_free(dcrn); #endif } @@ -5754,7 +5754,8 @@ static void gen_mfdcrx(DisasContext *ctx) } /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, + cpu_gpr[rA(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ #endif } @@ -5772,7 +5773,8 @@ static void gen_mtdcrx(DisasContext *ctx) } /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_helper_store_dcr(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rS(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ #endif } @@ -5782,7 +5784,8 @@ static void gen_mfdcrux(DisasContext *ctx) { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, + cpu_gpr[rA(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ } @@ -5791,7 +5794,8 @@ static void gen_mtdcrux(DisasContext *ctx) { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_helper_store_dcr(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_dcr(cpu_gpr[rA(ctx->opcode)], cpu_env, + cpu_gpr[rS(ctx->opcode)]); /* Note: Rc update flag set leads to undefined state of Rc0 */ } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 1e15fd9aef..f3a8aa554f 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -159,7 +159,7 @@ static void spr_read_decr (void *opaque, int gprn, int sprn) if (use_icount) { gen_io_start(); } - gen_helper_load_decr(cpu_gpr[gprn]); + gen_helper_load_decr(cpu_gpr[gprn], cpu_env); if (use_icount) { gen_io_end(); gen_stop_exception(opaque); @@ -171,7 +171,7 @@ static void spr_write_decr (void *opaque, int sprn, int gprn) if (use_icount) { gen_io_start(); } - gen_helper_store_decr(cpu_gpr[gprn]); + gen_helper_store_decr(cpu_env, cpu_gpr[gprn]); if (use_icount) { gen_io_end(); gen_stop_exception(opaque); @@ -186,7 +186,7 @@ static void spr_read_tbl (void *opaque, int gprn, int sprn) if (use_icount) { gen_io_start(); } - gen_helper_load_tbl(cpu_gpr[gprn]); + gen_helper_load_tbl(cpu_gpr[gprn], cpu_env); if (use_icount) { gen_io_end(); gen_stop_exception(opaque); @@ -198,7 +198,7 @@ static void spr_read_tbu (void *opaque, int gprn, int sprn) if (use_icount) { gen_io_start(); } - gen_helper_load_tbu(cpu_gpr[gprn]); + gen_helper_load_tbu(cpu_gpr[gprn], cpu_env); if (use_icount) { gen_io_end(); gen_stop_exception(opaque); @@ -208,13 +208,13 @@ static void spr_read_tbu (void *opaque, int gprn, int sprn) __attribute__ (( unused )) static void spr_read_atbl (void *opaque, int gprn, int sprn) { - gen_helper_load_atbl(cpu_gpr[gprn]); + gen_helper_load_atbl(cpu_gpr[gprn], cpu_env); } __attribute__ (( unused )) static void spr_read_atbu (void *opaque, int gprn, int sprn) { - gen_helper_load_atbu(cpu_gpr[gprn]); + gen_helper_load_atbu(cpu_gpr[gprn], cpu_env); } #if !defined(CONFIG_USER_ONLY) @@ -223,7 +223,7 @@ static void spr_write_tbl (void *opaque, int sprn, int gprn) if (use_icount) { gen_io_start(); } - gen_helper_store_tbl(cpu_gpr[gprn]); + gen_helper_store_tbl(cpu_env, cpu_gpr[gprn]); if (use_icount) { gen_io_end(); gen_stop_exception(opaque); @@ -235,7 +235,7 @@ static void spr_write_tbu (void *opaque, int sprn, int gprn) if (use_icount) { gen_io_start(); } - gen_helper_store_tbu(cpu_gpr[gprn]); + gen_helper_store_tbu(cpu_env, cpu_gpr[gprn]); if (use_icount) { gen_io_end(); gen_stop_exception(opaque); @@ -245,20 +245,20 @@ static void spr_write_tbu (void *opaque, int sprn, int gprn) __attribute__ (( unused )) static void spr_write_atbl (void *opaque, int sprn, int gprn) { - gen_helper_store_atbl(cpu_gpr[gprn]); + gen_helper_store_atbl(cpu_env, cpu_gpr[gprn]); } __attribute__ (( unused )) static void spr_write_atbu (void *opaque, int sprn, int gprn) { - gen_helper_store_atbu(cpu_gpr[gprn]); + gen_helper_store_atbu(cpu_env, cpu_gpr[gprn]); } #if defined(TARGET_PPC64) __attribute__ (( unused )) static void spr_read_purr (void *opaque, int gprn, int sprn) { - gen_helper_load_purr(cpu_gpr[gprn]); + gen_helper_load_purr(cpu_gpr[gprn], cpu_env); } #endif #endif @@ -382,23 +382,23 @@ static void spr_write_asr (void *opaque, int sprn, int gprn) /* RTC */ static void spr_read_601_rtcl (void *opaque, int gprn, int sprn) { - gen_helper_load_601_rtcl(cpu_gpr[gprn]); + gen_helper_load_601_rtcl(cpu_gpr[gprn], cpu_env); } static void spr_read_601_rtcu (void *opaque, int gprn, int sprn) { - gen_helper_load_601_rtcu(cpu_gpr[gprn]); + gen_helper_load_601_rtcu(cpu_gpr[gprn], cpu_env); } #if !defined(CONFIG_USER_ONLY) static void spr_write_601_rtcu (void *opaque, int sprn, int gprn) { - gen_helper_store_601_rtcu(cpu_gpr[gprn]); + gen_helper_store_601_rtcu(cpu_env, cpu_gpr[gprn]); } static void spr_write_601_rtcl (void *opaque, int sprn, int gprn) { - gen_helper_store_601_rtcl(cpu_gpr[gprn]); + gen_helper_store_601_rtcl(cpu_env, cpu_gpr[gprn]); } static void spr_write_hid0_601 (void *opaque, int sprn, int gprn) @@ -437,12 +437,12 @@ static void spr_write_601_ubatl (void *opaque, int sprn, int gprn) #if !defined(CONFIG_USER_ONLY) static void spr_read_40x_pit (void *opaque, int gprn, int sprn) { - gen_helper_load_40x_pit(cpu_gpr[gprn]); + gen_helper_load_40x_pit(cpu_gpr[gprn], cpu_env); } static void spr_write_40x_pit (void *opaque, int sprn, int gprn) { - gen_helper_store_40x_pit(cpu_gpr[gprn]); + gen_helper_store_40x_pit(cpu_env, cpu_gpr[gprn]); } static void spr_write_40x_dbcr0 (void *opaque, int sprn, int gprn) @@ -461,12 +461,12 @@ static void spr_write_40x_sler (void *opaque, int sprn, int gprn) static void spr_write_booke_tcr (void *opaque, int sprn, int gprn) { - gen_helper_store_booke_tcr(cpu_gpr[gprn]); + gen_helper_store_booke_tcr(cpu_env, cpu_gpr[gprn]); } static void spr_write_booke_tsr (void *opaque, int sprn, int gprn) { - gen_helper_store_booke_tsr(cpu_gpr[gprn]); + gen_helper_store_booke_tsr(cpu_env, cpu_gpr[gprn]); } #endif From 901c4eaf9670060c837987dac7912e5ab46df58a Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:37 +0000 Subject: [PATCH 17/72] ppc: Split off misc helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move misc helpers from op_helper.c to misc_helpers.c. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 2 + target-ppc/misc_helper.c | 116 +++++++++++++++++++++++++++++++++++++++ target-ppc/op_helper.c | 94 ------------------------------- 3 files changed, 118 insertions(+), 94 deletions(-) create mode 100644 target-ppc/misc_helper.c diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 4a8864115d..3a444eb77a 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -7,5 +7,7 @@ obj-y += fpu_helper.o obj-y += int_helper.o obj-y += mmu_helper.o obj-y += timebase_helper.o +obj-y += misc_helper.o +$(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c new file mode 100644 index 0000000000..67eab0853f --- /dev/null +++ b/target-ppc/misc_helper.c @@ -0,0 +1,116 @@ +/* + * Miscellaneous PowerPC emulation 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, see . + */ +#include "cpu.h" +#include "dyngen-exec.h" +#include "helper.h" + +#include "helper_regs.h" + +/*****************************************************************************/ +/* SPR accesses */ +void helper_load_dump_spr(uint32_t sprn) +{ + qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn, + env->spr[sprn]); +} + +void helper_store_dump_spr(uint32_t sprn) +{ + qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn, + env->spr[sprn]); +} +#if !defined(CONFIG_USER_ONLY) +#if defined(TARGET_PPC64) +void helper_store_asr(target_ulong val) +{ + ppc_store_asr(env, val); +} +#endif + +void helper_store_sdr1(target_ulong val) +{ + ppc_store_sdr1(env, val); +} + +void helper_store_hid0_601(target_ulong val) +{ + target_ulong hid0; + + hid0 = env->spr[SPR_HID0]; + if ((val ^ hid0) & 0x00000008) { + /* Change current endianness */ + env->hflags &= ~(1 << MSR_LE); + env->hflags_nmsr &= ~(1 << MSR_LE); + env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE); + env->hflags |= env->hflags_nmsr; + qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__, + val & 0x8 ? 'l' : 'b', env->hflags); + } + env->spr[SPR_HID0] = (uint32_t)val; +} + +void helper_store_403_pbr(uint32_t num, target_ulong value) +{ + if (likely(env->pb[num] != value)) { + env->pb[num] = value; + /* Should be optimized */ + tlb_flush(env, 1); + } +} + +void helper_store_40x_dbcr0(target_ulong val) +{ + store_40x_dbcr0(env, val); +} + +void helper_store_40x_sler(target_ulong val) +{ + store_40x_sler(env, val); +} +#endif +/*****************************************************************************/ +/* PowerPC 601 specific instructions (POWER bridge) */ + +target_ulong helper_clcs(uint32_t arg) +{ + switch (arg) { + case 0x0CUL: + /* Instruction cache line size */ + return env->icache_line_size; + break; + case 0x0DUL: + /* Data cache line size */ + return env->dcache_line_size; + break; + case 0x0EUL: + /* Minimum cache line size */ + return (env->icache_line_size < env->dcache_line_size) ? + env->icache_line_size : env->dcache_line_size; + break; + case 0x0FUL: + /* Maximum cache line size */ + return (env->icache_line_size > env->dcache_line_size) ? + env->icache_line_size : env->dcache_line_size; + break; + default: + /* Undefined */ + return 0; + break; + } +} diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 09299068fc..cd1a53322c 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -30,69 +30,6 @@ //#define DEBUG_OP -/*****************************************************************************/ -/* SPR accesses */ -void helper_load_dump_spr(uint32_t sprn) -{ - qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn, - env->spr[sprn]); -} - -void helper_store_dump_spr(uint32_t sprn) -{ - qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn, - env->spr[sprn]); -} -#if !defined(CONFIG_USER_ONLY) -#if defined(TARGET_PPC64) -void helper_store_asr(target_ulong val) -{ - ppc_store_asr(env, val); -} -#endif - -void helper_store_sdr1(target_ulong val) -{ - ppc_store_sdr1(env, val); -} - -void helper_store_hid0_601(target_ulong val) -{ - target_ulong hid0; - - hid0 = env->spr[SPR_HID0]; - if ((val ^ hid0) & 0x00000008) { - /* Change current endianness */ - env->hflags &= ~(1 << MSR_LE); - env->hflags_nmsr &= ~(1 << MSR_LE); - env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE); - env->hflags |= env->hflags_nmsr; - qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__, - val & 0x8 ? 'l' : 'b', env->hflags); - } - env->spr[SPR_HID0] = (uint32_t)val; -} - -void helper_store_403_pbr(uint32_t num, target_ulong value) -{ - if (likely(env->pb[num] != value)) { - env->pb[num] = value; - /* Should be optimized */ - tlb_flush(env, 1); - } -} - -void helper_store_40x_dbcr0(target_ulong val) -{ - store_40x_dbcr0(env, val); -} - -void helper_store_40x_sler(target_ulong val) -{ - store_40x_sler(env, val); -} -#endif - /*****************************************************************************/ /* Memory load and stores */ @@ -251,37 +188,6 @@ target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra, return i; } -/*****************************************************************************/ -/* PowerPC 601 specific instructions (POWER bridge) */ - -target_ulong helper_clcs(uint32_t arg) -{ - switch (arg) { - case 0x0CUL: - /* Instruction cache line size */ - return env->icache_line_size; - break; - case 0x0DUL: - /* Data cache line size */ - return env->dcache_line_size; - break; - case 0x0EUL: - /* Minimum cache line size */ - return (env->icache_line_size < env->dcache_line_size) ? - env->icache_line_size : env->dcache_line_size; - break; - case 0x0FUL: - /* Maximum cache line size */ - return (env->icache_line_size > env->dcache_line_size) ? - env->icache_line_size : env->dcache_line_size; - break; - default: - /* Undefined */ - return 0; - break; - } -} - /*****************************************************************************/ /* Altivec extension helpers */ #if defined(HOST_WORDS_BIGENDIAN) From d523dd00a7d73b28f2e99acf45a4b3f92e56e40a Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:38 +0000 Subject: [PATCH 18/72] ppc: Avoid AREG0 for misc helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an explicit CPUPPCState parameter instead of relying on AREG0. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 1 - target-ppc/helper.h | 18 +++++++++--------- target-ppc/misc_helper.c | 19 +++++++++---------- target-ppc/translate.c | 2 +- target-ppc/translate_init.c | 12 ++++++------ 5 files changed, 25 insertions(+), 27 deletions(-) diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 3a444eb77a..8d4d16baf3 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -9,5 +9,4 @@ obj-y += mmu_helper.o obj-y += timebase_helper.o obj-y += misc_helper.o -$(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 81fc40eb1a..b7a157e35e 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -363,7 +363,7 @@ DEF_HELPER_2(msgclr, void, env, tl) #endif DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32) -DEF_HELPER_FLAGS_1(clcs, TCG_CALL_CONST | TCG_CALL_PURE, tl, i32) +DEF_HELPER_FLAGS_2(clcs, TCG_CALL_CONST | TCG_CALL_PURE, tl, env, i32) #if !defined(CONFIG_USER_ONLY) DEF_HELPER_2(rac, tl, env, tl) #endif @@ -375,8 +375,8 @@ DEF_HELPER_3(divso, tl, env, tl, tl) DEF_HELPER_2(load_dcr, tl, env, tl); DEF_HELPER_3(store_dcr, void, env, tl, tl) -DEF_HELPER_1(load_dump_spr, void, i32) -DEF_HELPER_1(store_dump_spr, void, i32) +DEF_HELPER_2(load_dump_spr, void, env, i32) +DEF_HELPER_2(store_dump_spr, void, env, i32) DEF_HELPER_1(load_tbl, tl, env) DEF_HELPER_1(load_tbu, tl, env) DEF_HELPER_1(load_atbl, tl, env) @@ -385,10 +385,10 @@ DEF_HELPER_1(load_601_rtcl, tl, env) DEF_HELPER_1(load_601_rtcu, tl, env) #if !defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) -DEF_HELPER_1(store_asr, void, tl) +DEF_HELPER_2(store_asr, void, env, tl) DEF_HELPER_1(load_purr, tl, env) #endif -DEF_HELPER_1(store_sdr1, void, tl) +DEF_HELPER_2(store_sdr1, void, env, tl) DEF_HELPER_2(store_tbl, void, env, tl) DEF_HELPER_2(store_tbu, void, env, tl) DEF_HELPER_2(store_atbl, void, env, tl) @@ -397,12 +397,12 @@ DEF_HELPER_2(store_601_rtcl, void, env, tl) DEF_HELPER_2(store_601_rtcu, void, env, tl) DEF_HELPER_1(load_decr, tl, env) DEF_HELPER_2(store_decr, void, env, tl) -DEF_HELPER_1(store_hid0_601, void, tl) -DEF_HELPER_2(store_403_pbr, void, i32, tl) +DEF_HELPER_2(store_hid0_601, void, env, tl) +DEF_HELPER_3(store_403_pbr, void, env, i32, tl) DEF_HELPER_1(load_40x_pit, tl, env) DEF_HELPER_2(store_40x_pit, void, env, tl) -DEF_HELPER_1(store_40x_dbcr0, void, tl) -DEF_HELPER_1(store_40x_sler, void, tl) +DEF_HELPER_2(store_40x_dbcr0, void, env, tl) +DEF_HELPER_2(store_40x_sler, void, env, tl) DEF_HELPER_2(store_booke_tcr, void, env, tl) DEF_HELPER_2(store_booke_tsr, void, env, tl) DEF_HELPER_3(store_ibatl, void, env, i32, tl) diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c index 67eab0853f..b194d1987d 100644 --- a/target-ppc/misc_helper.c +++ b/target-ppc/misc_helper.c @@ -17,38 +17,37 @@ * License along with this library; if not, see . */ #include "cpu.h" -#include "dyngen-exec.h" #include "helper.h" #include "helper_regs.h" /*****************************************************************************/ /* SPR accesses */ -void helper_load_dump_spr(uint32_t sprn) +void helper_load_dump_spr(CPUPPCState *env, uint32_t sprn) { qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn, env->spr[sprn]); } -void helper_store_dump_spr(uint32_t sprn) +void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn) { qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn, env->spr[sprn]); } #if !defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) -void helper_store_asr(target_ulong val) +void helper_store_asr(CPUPPCState *env, target_ulong val) { ppc_store_asr(env, val); } #endif -void helper_store_sdr1(target_ulong val) +void helper_store_sdr1(CPUPPCState *env, target_ulong val) { ppc_store_sdr1(env, val); } -void helper_store_hid0_601(target_ulong val) +void helper_store_hid0_601(CPUPPCState *env, target_ulong val) { target_ulong hid0; @@ -65,7 +64,7 @@ void helper_store_hid0_601(target_ulong val) env->spr[SPR_HID0] = (uint32_t)val; } -void helper_store_403_pbr(uint32_t num, target_ulong value) +void helper_store_403_pbr(CPUPPCState *env, uint32_t num, target_ulong value) { if (likely(env->pb[num] != value)) { env->pb[num] = value; @@ -74,12 +73,12 @@ void helper_store_403_pbr(uint32_t num, target_ulong value) } } -void helper_store_40x_dbcr0(target_ulong val) +void helper_store_40x_dbcr0(CPUPPCState *env, target_ulong val) { store_40x_dbcr0(env, val); } -void helper_store_40x_sler(target_ulong val) +void helper_store_40x_sler(CPUPPCState *env, target_ulong val) { store_40x_sler(env, val); } @@ -87,7 +86,7 @@ void helper_store_40x_sler(target_ulong val) /*****************************************************************************/ /* PowerPC 601 specific instructions (POWER bridge) */ -target_ulong helper_clcs(uint32_t arg) +target_ulong helper_clcs(CPUPPCState *env, uint32_t arg) { switch (arg) { case 0x0CUL: diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 5eec4b040b..bcc993313d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4551,7 +4551,7 @@ static void gen_abso(DisasContext *ctx) static void gen_clcs(DisasContext *ctx) { TCGv_i32 t0 = tcg_const_i32(rA(ctx->opcode)); - gen_helper_clcs(cpu_gpr[rD(ctx->opcode)], t0); + gen_helper_clcs(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); tcg_temp_free_i32(t0); /* Rc=1 sets CR0 to an undefined state */ } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f3a8aa554f..f6ac589a53 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -347,7 +347,7 @@ static void spr_write_dbatl_h (void *opaque, int sprn, int gprn) /* SDR1 */ static void spr_write_sdr1 (void *opaque, int sprn, int gprn) { - gen_helper_store_sdr1(cpu_gpr[gprn]); + gen_helper_store_sdr1(cpu_env, cpu_gpr[gprn]); } /* 64 bits PowerPC specific SPRs */ @@ -373,7 +373,7 @@ static void spr_read_asr (void *opaque, int gprn, int sprn) static void spr_write_asr (void *opaque, int sprn, int gprn) { - gen_helper_store_asr(cpu_gpr[gprn]); + gen_helper_store_asr(cpu_env, cpu_gpr[gprn]); } #endif #endif @@ -405,7 +405,7 @@ static void spr_write_hid0_601 (void *opaque, int sprn, int gprn) { DisasContext *ctx = opaque; - gen_helper_store_hid0_601(cpu_gpr[gprn]); + gen_helper_store_hid0_601(cpu_env, cpu_gpr[gprn]); /* Must stop the translation as endianness may have changed */ gen_stop_exception(ctx); } @@ -449,14 +449,14 @@ static void spr_write_40x_dbcr0 (void *opaque, int sprn, int gprn) { DisasContext *ctx = opaque; - gen_helper_store_40x_dbcr0(cpu_gpr[gprn]); + gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]); /* We must stop translation as we may have rebooted */ gen_stop_exception(ctx); } static void spr_write_40x_sler (void *opaque, int sprn, int gprn) { - gen_helper_store_40x_sler(cpu_gpr[gprn]); + gen_helper_store_40x_sler(cpu_env, cpu_gpr[gprn]); } static void spr_write_booke_tcr (void *opaque, int sprn, int gprn) @@ -481,7 +481,7 @@ static void spr_read_403_pbr (void *opaque, int gprn, int sprn) static void spr_write_403_pbr (void *opaque, int sprn, int gprn) { TCGv_i32 t0 = tcg_const_i32(sprn - SPR_403_PBL1); - gen_helper_store_403_pbr(t0, cpu_gpr[gprn]); + gen_helper_store_403_pbr(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } From 8555f71dcbbe562429bbb25e0028f71e5741b752 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:39 +0000 Subject: [PATCH 19/72] ppc: Move misc helpers from helper.c to misc_helper.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move more misc helpers from helper.c to misc_helper.c. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/helper.c | 9 --------- target-ppc/misc_helper.c | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 24d109d992..48b19a7e1d 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -23,15 +23,6 @@ #include "kvm_ppc.h" #include "cpus.h" -/*****************************************************************************/ -/* Special registers manipulation */ - -/* GDBstub can read and write MSR... */ -void ppc_store_msr(CPUPPCState *env, target_ulong value) -{ - hreg_store_msr(env, value, 0); -} - PowerPCCPU *cpu_ppc_init(const char *cpu_model) { PowerPCCPU *cpu; diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c index b194d1987d..26edcca2df 100644 --- a/target-ppc/misc_helper.c +++ b/target-ppc/misc_helper.c @@ -113,3 +113,12 @@ target_ulong helper_clcs(CPUPPCState *env, uint32_t arg) break; } } + +/*****************************************************************************/ +/* Special registers manipulation */ + +/* GDBstub can read and write MSR... */ +void ppc_store_msr(CPUPPCState *env, target_ulong value) +{ + hreg_store_msr(env, value, 0); +} From 2f5a189caefe2ecbd32faf528a0fbf8c915dfa08 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:40 +0000 Subject: [PATCH 20/72] ppc: Move load and store helpers, switch to AREG0 free mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an explicit CPUPPCState parameter instead of relying on AREG0 and rename op_helper.c (which only contains load and store helpers) to mem_helper.c. Remove AREG0 swapping in tlb_fill(). Switch to AREG0 free mode. Use cpu_ld{l,uw}_code in translation and interrupt handling, cpu_{ld,st}{l,uw}_data in loads and stores. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- configure | 2 +- cpu-all.h | 9 ++ target-ppc/Makefile.objs | 7 +- target-ppc/excp_helper.c | 3 +- target-ppc/helper.h | 30 +++---- target-ppc/{op_helper.c => mem_helper.c} | 109 ++++++++++++----------- target-ppc/translate.c | 30 +++---- 7 files changed, 100 insertions(+), 90 deletions(-) rename target-ppc/{op_helper.c => mem_helper.c} (68%) diff --git a/configure b/configure index b68c0ca194..6128ba7522 100755 --- a/configure +++ b/configure @@ -3679,7 +3679,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" case "$target_arch2" in - alpha | sparc* | xtensa*) + alpha | sparc* | xtensa* | ppc*) echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak ;; esac diff --git a/cpu-all.h b/cpu-all.h index 50c8b62583..9dc249a165 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -291,6 +291,15 @@ extern unsigned long reserved_va; #define stfl_kernel(p, v) stfl_raw(p, v) #define stfq_kernel(p, vt) stfq_raw(p, v) +#ifdef CONFIG_TCG_PASS_AREG0 +#define cpu_ldub_data(env, addr) ldub_raw(addr) +#define cpu_lduw_data(env, addr) lduw_raw(addr) +#define cpu_ldl_data(env, addr) ldl_raw(addr) + +#define cpu_stb_data(env, addr, data) stb_raw(addr, data) +#define cpu_stw_data(env, addr, data) stw_raw(addr, data) +#define cpu_stl_data(env, addr, data) stl_raw(addr, data) +#endif #endif /* defined(CONFIG_USER_ONLY) */ /* page related stuff */ diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 8d4d16baf3..6c11ef84b7 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -1,12 +1,11 @@ -obj-y += translate.o op_helper.o helper.o +obj-y += translate.o helper.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o -obj-y += op_helper.o helper.o +obj-y += helper.o obj-y += excp_helper.o obj-y += fpu_helper.o obj-y += int_helper.o obj-y += mmu_helper.o obj-y += timebase_helper.o obj-y += misc_helper.o - -$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +obj-y += mem_helper.o diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 7fa7a59b4f..c7762b99c5 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -179,7 +179,8 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) } /* XXX: this is false */ /* Get rS/rD and rA from faulting opcode */ - env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; + env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4)) + & 0x03FF0000) >> 16; goto store_current; case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { diff --git a/target-ppc/helper.h b/target-ppc/helper.h index b7a157e35e..ddab97b379 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -20,15 +20,15 @@ DEF_HELPER_1(hrfid, void, env) #endif #endif -DEF_HELPER_2(lmw, void, tl, i32) -DEF_HELPER_2(stmw, void, tl, i32) -DEF_HELPER_3(lsw, void, tl, i32, i32) -DEF_HELPER_4(lswx, void, tl, i32, i32, i32) -DEF_HELPER_3(stsw, void, tl, i32, i32) -DEF_HELPER_1(dcbz, void, tl) -DEF_HELPER_1(dcbz_970, void, tl) -DEF_HELPER_1(icbi, void, tl) -DEF_HELPER_4(lscbx, tl, tl, i32, i32, i32) +DEF_HELPER_3(lmw, void, env, tl, i32) +DEF_HELPER_3(stmw, void, env, tl, i32) +DEF_HELPER_4(lsw, void, env, tl, i32, i32) +DEF_HELPER_5(lswx, void, env, tl, i32, i32, i32) +DEF_HELPER_4(stsw, void, env, tl, i32, i32) +DEF_HELPER_2(dcbz, void, env, tl) +DEF_HELPER_2(dcbz_970, void, env, tl) +DEF_HELPER_2(icbi, void, env, tl) +DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32) #if defined(TARGET_PPC64) DEF_HELPER_FLAGS_2(mulhd, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64) @@ -226,12 +226,12 @@ DEF_HELPER_5(vmsumshm, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmsumshs, void, env, avr, avr, avr, avr) DEF_HELPER_4(vmladduhm, void, avr, avr, avr, avr) DEF_HELPER_2(mtvscr, void, env, avr); -DEF_HELPER_2(lvebx, void, avr, tl) -DEF_HELPER_2(lvehx, void, avr, tl) -DEF_HELPER_2(lvewx, void, avr, tl) -DEF_HELPER_2(stvebx, void, avr, tl) -DEF_HELPER_2(stvehx, void, avr, tl) -DEF_HELPER_2(stvewx, void, avr, tl) +DEF_HELPER_3(lvebx, void, env, avr, tl) +DEF_HELPER_3(lvehx, void, env, avr, tl) +DEF_HELPER_3(lvewx, void, env, avr, tl) +DEF_HELPER_3(stvebx, void, env, avr, tl) +DEF_HELPER_3(stvehx, void, env, avr, tl) +DEF_HELPER_3(stvewx, void, env, avr, tl) DEF_HELPER_4(vsumsws, void, env, avr, avr, avr) DEF_HELPER_4(vsum2sws, void, env, avr, avr, avr) DEF_HELPER_4(vsum4sbs, void, env, avr, avr, avr) diff --git a/target-ppc/op_helper.c b/target-ppc/mem_helper.c similarity index 68% rename from target-ppc/op_helper.c rename to target-ppc/mem_helper.c index cd1a53322c..ebcd7b24a8 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/mem_helper.c @@ -1,5 +1,5 @@ /* - * PowerPC emulation helpers for QEMU. + * PowerPC memory access emulation helpers for QEMU. * * Copyright (c) 2003-2007 Jocelyn Mayer * @@ -16,9 +16,7 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ -#include #include "cpu.h" -#include "dyngen-exec.h" #include "host-utils.h" #include "helper.h" @@ -33,7 +31,8 @@ /*****************************************************************************/ /* Memory load and stores */ -static inline target_ulong addr_add(target_ulong addr, target_long arg) +static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr, + target_long arg) { #if defined(TARGET_PPC64) if (!msr_sf) { @@ -45,44 +44,44 @@ static inline target_ulong addr_add(target_ulong addr, target_long arg) } } -void helper_lmw(target_ulong addr, uint32_t reg) +void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg) { for (; reg < 32; reg++) { if (msr_le) { - env->gpr[reg] = bswap32(ldl(addr)); + env->gpr[reg] = bswap32(cpu_ldl_data(env, addr)); } else { - env->gpr[reg] = ldl(addr); + env->gpr[reg] = cpu_ldl_data(env, addr); } - addr = addr_add(addr, 4); + addr = addr_add(env, addr, 4); } } -void helper_stmw(target_ulong addr, uint32_t reg) +void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg) { for (; reg < 32; reg++) { if (msr_le) { - stl(addr, bswap32((uint32_t)env->gpr[reg])); + cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg])); } else { - stl(addr, (uint32_t)env->gpr[reg]); + cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]); } - addr = addr_add(addr, 4); + addr = addr_add(env, addr, 4); } } -void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg) +void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg) { int sh; for (; nb > 3; nb -= 4) { - env->gpr[reg] = ldl(addr); + env->gpr[reg] = cpu_ldl_data(env, addr); reg = (reg + 1) % 32; - addr = addr_add(addr, 4); + addr = addr_add(env, addr, 4); } if (unlikely(nb > 0)) { env->gpr[reg] = 0; for (sh = 24; nb > 0; nb--, sh -= 8) { - env->gpr[reg] |= ldub(addr) << sh; - addr = addr_add(addr, 1); + env->gpr[reg] |= cpu_ldub_data(env, addr) << sh; + addr = addr_add(env, addr, 1); } } } @@ -91,7 +90,8 @@ void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg) * In an other hand, IBM says this is valid, but rA won't be loaded. * For now, I'll follow the spec... */ -void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb) +void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg, + uint32_t ra, uint32_t rb) { if (likely(xer_bc != 0)) { if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) || @@ -100,56 +100,57 @@ void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb) POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_LSWX); } else { - helper_lsw(addr, xer_bc, reg); + helper_lsw(env, addr, xer_bc, reg); } } } -void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg) +void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb, + uint32_t reg) { int sh; for (; nb > 3; nb -= 4) { - stl(addr, env->gpr[reg]); + cpu_stl_data(env, addr, env->gpr[reg]); reg = (reg + 1) % 32; - addr = addr_add(addr, 4); + addr = addr_add(env, addr, 4); } if (unlikely(nb > 0)) { for (sh = 24; nb > 0; nb--, sh -= 8) { - stb(addr, (env->gpr[reg] >> sh) & 0xFF); - addr = addr_add(addr, 1); + cpu_stb_data(env, addr, (env->gpr[reg] >> sh) & 0xFF); + addr = addr_add(env, addr, 1); } } } -static void do_dcbz(target_ulong addr, int dcache_line_size) +static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size) { int i; addr &= ~(dcache_line_size - 1); for (i = 0; i < dcache_line_size; i += 4) { - stl(addr + i, 0); + cpu_stl_data(env, addr + i, 0); } if (env->reserve_addr == addr) { env->reserve_addr = (target_ulong)-1ULL; } } -void helper_dcbz(target_ulong addr) +void helper_dcbz(CPUPPCState *env, target_ulong addr) { - do_dcbz(addr, env->dcache_line_size); + do_dcbz(env, addr, env->dcache_line_size); } -void helper_dcbz_970(target_ulong addr) +void helper_dcbz_970(CPUPPCState *env, target_ulong addr) { if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) { - do_dcbz(addr, 32); + do_dcbz(env, addr, 32); } else { - do_dcbz(addr, env->dcache_line_size); + do_dcbz(env, addr, env->dcache_line_size); } } -void helper_icbi(target_ulong addr) +void helper_icbi(CPUPPCState *env, target_ulong addr) { addr &= ~(env->dcache_line_size - 1); /* Invalidate one cache line : @@ -157,19 +158,19 @@ void helper_icbi(target_ulong addr) * (not a fetch) by the MMU. To be sure it will be so, * do the load "by hand". */ - ldl(addr); + cpu_ldl_data(env, addr); } /* XXX: to be tested */ -target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra, - uint32_t rb) +target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg, + uint32_t ra, uint32_t rb) { int i, c, d; d = 24; for (i = 0; i < xer_bc; i++) { - c = ldub(addr); - addr = addr_add(addr, 1); + c = cpu_ldub_data(env, addr); + addr = addr_add(env, addr, 1); /* ra (if not 0) and rb are never modified */ if (likely(reg != rb && (ra == 0 || reg != ra))) { env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d); @@ -199,7 +200,8 @@ target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra, #endif #define LVE(name, access, swap, element) \ - void helper_##name(ppc_avr_t *r, target_ulong addr) \ + void helper_##name(CPUPPCState *env, ppc_avr_t *r, \ + target_ulong addr) \ { \ size_t n_elems = ARRAY_SIZE(r->element); \ int adjust = HI_IDX*(n_elems - 1); \ @@ -208,21 +210,22 @@ target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra, \ if (msr_le) { \ r->element[LO_IDX ? index : (adjust - index)] = \ - swap(access(addr)); \ + swap(access(env, addr)); \ } else { \ r->element[LO_IDX ? index : (adjust - index)] = \ - access(addr); \ + access(env, addr); \ } \ } #define I(x) (x) -LVE(lvebx, ldub, I, u8) -LVE(lvehx, lduw, bswap16, u16) -LVE(lvewx, ldl, bswap32, u32) +LVE(lvebx, cpu_ldub_data, I, u8) +LVE(lvehx, cpu_lduw_data, bswap16, u16) +LVE(lvewx, cpu_ldl_data, bswap32, u32) #undef I #undef LVE #define STVE(name, access, swap, element) \ - void helper_##name(ppc_avr_t *r, target_ulong addr) \ + void helper_##name(CPUPPCState *env, ppc_avr_t *r, \ + target_ulong addr) \ { \ size_t n_elems = ARRAY_SIZE(r->element); \ int adjust = HI_IDX * (n_elems - 1); \ @@ -230,15 +233,17 @@ LVE(lvewx, ldl, bswap32, u32) int index = (addr & 0xf) >> sh; \ \ if (msr_le) { \ - access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \ + access(env, addr, swap(r->element[LO_IDX ? index : \ + (adjust - index)])); \ } else { \ - access(addr, r->element[LO_IDX ? index : (adjust - index)]); \ + access(env, addr, r->element[LO_IDX ? index : \ + (adjust - index)]); \ } \ } #define I(x) (x) -STVE(stvebx, stb, I, u8) -STVE(stvehx, stw, bswap16, u16) -STVE(stvewx, stl, bswap32, u32) +STVE(stvebx, cpu_stb_data, I, u8) +STVE(stvehx, cpu_stw_data, bswap16, u16) +STVE(stvewx, cpu_stl_data, bswap32, u32) #undef I #undef LVE @@ -267,15 +272,12 @@ STVE(stvewx, stl, bswap32, u32) NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx, +void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx, uintptr_t retaddr) { TranslationBlock *tb; - CPUPPCState *saved_env; int ret; - saved_env = env; - env = env1; ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx); if (unlikely(ret != 0)) { if (likely(retaddr)) { @@ -289,6 +291,5 @@ void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx, } helper_raise_exception_err(env, env->exception_index, env->error_code); } - env = saved_env; } #endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index bcc993313d..9103fd5776 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2989,7 +2989,7 @@ static void gen_lmw(DisasContext *ctx) t0 = tcg_temp_new(); t1 = tcg_const_i32(rD(ctx->opcode)); gen_addr_imm_index(ctx, t0, 0); - gen_helper_lmw(t0, t1); + gen_helper_lmw(cpu_env, t0, t1); tcg_temp_free(t0); tcg_temp_free_i32(t1); } @@ -3005,7 +3005,7 @@ static void gen_stmw(DisasContext *ctx) t0 = tcg_temp_new(); t1 = tcg_const_i32(rS(ctx->opcode)); gen_addr_imm_index(ctx, t0, 0); - gen_helper_stmw(t0, t1); + gen_helper_stmw(cpu_env, t0, t1); tcg_temp_free(t0); tcg_temp_free_i32(t1); } @@ -3043,7 +3043,7 @@ static void gen_lswi(DisasContext *ctx) gen_addr_register(ctx, t0); t1 = tcg_const_i32(nb); t2 = tcg_const_i32(start); - gen_helper_lsw(t0, t1, t2); + gen_helper_lsw(cpu_env, t0, t1, t2); tcg_temp_free(t0); tcg_temp_free_i32(t1); tcg_temp_free_i32(t2); @@ -3062,7 +3062,7 @@ static void gen_lswx(DisasContext *ctx) t1 = tcg_const_i32(rD(ctx->opcode)); t2 = tcg_const_i32(rA(ctx->opcode)); t3 = tcg_const_i32(rB(ctx->opcode)); - gen_helper_lswx(t0, t1, t2, t3); + gen_helper_lswx(cpu_env, t0, t1, t2, t3); tcg_temp_free(t0); tcg_temp_free_i32(t1); tcg_temp_free_i32(t2); @@ -3084,7 +3084,7 @@ static void gen_stswi(DisasContext *ctx) nb = 32; t1 = tcg_const_i32(nb); t2 = tcg_const_i32(rS(ctx->opcode)); - gen_helper_stsw(t0, t1, t2); + gen_helper_stsw(cpu_env, t0, t1, t2); tcg_temp_free(t0); tcg_temp_free_i32(t1); tcg_temp_free_i32(t2); @@ -3104,7 +3104,7 @@ static void gen_stswx(DisasContext *ctx) tcg_gen_trunc_tl_i32(t1, cpu_xer); tcg_gen_andi_i32(t1, t1, 0x7F); t2 = tcg_const_i32(rS(ctx->opcode)); - gen_helper_stsw(t0, t1, t2); + gen_helper_stsw(cpu_env, t0, t1, t2); tcg_temp_free(t0); tcg_temp_free_i32(t1); tcg_temp_free_i32(t2); @@ -4116,7 +4116,7 @@ static void gen_dcbz(DisasContext *ctx) gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_dcbz(t0); + gen_helper_dcbz(cpu_env, t0); tcg_temp_free(t0); } @@ -4129,9 +4129,9 @@ static void gen_dcbz_970(DisasContext *ctx) t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); if (ctx->opcode & 0x00200000) - gen_helper_dcbz(t0); + gen_helper_dcbz(cpu_env, t0); else - gen_helper_dcbz_970(t0); + gen_helper_dcbz_970(cpu_env, t0); tcg_temp_free(t0); } @@ -4171,7 +4171,7 @@ static void gen_icbi(DisasContext *ctx) gen_update_nip(ctx, ctx->nip - 4); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_helper_icbi(t0); + gen_helper_icbi(cpu_env, t0); tcg_temp_free(t0); } @@ -4663,7 +4663,7 @@ static void gen_lscbx(DisasContext *ctx) gen_addr_reg_index(ctx, t0); /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_helper_lscbx(t0, t0, t1, t2, t3); + gen_helper_lscbx(t0, cpu_env, t0, t1, t2, t3); tcg_temp_free_i32(t1); tcg_temp_free_i32(t2); tcg_temp_free_i32(t3); @@ -6387,7 +6387,7 @@ static void gen_lve##name(DisasContext *ctx) \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ rs = gen_avr_ptr(rS(ctx->opcode)); \ - gen_helper_lve##name (rs, EA); \ + gen_helper_lve##name(cpu_env, rs, EA); \ tcg_temp_free(EA); \ tcg_temp_free_ptr(rs); \ } @@ -6405,7 +6405,7 @@ static void gen_stve##name(DisasContext *ctx) \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ rs = gen_avr_ptr(rS(ctx->opcode)); \ - gen_helper_stve##name (rs, EA); \ + gen_helper_stve##name(cpu_env, rs, EA); \ tcg_temp_free(EA); \ tcg_temp_free_ptr(rs); \ } @@ -9683,9 +9683,9 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); if (unlikely(ctx.le_mode)) { - ctx.opcode = bswap32(ldl_code(ctx.nip)); + ctx.opcode = bswap32(cpu_ldl_code(env, ctx.nip)); } else { - ctx.opcode = ldl_code(ctx.nip); + ctx.opcode = cpu_ldl_code(env, ctx.nip); } LOG_DISAS("translate opcode %08x (%02x %02x %02x) (%s)\n", ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), From 9063825538ad8fc9131191fceefcbb149fa5d199 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:41 +0000 Subject: [PATCH 21/72] ppc: Add missing break MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add obviously missing 'break' statement. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/fpu_helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c index d90636fad0..9d67926209 100644 --- a/target-ppc/fpu_helper.c +++ b/target-ppc/fpu_helper.c @@ -310,6 +310,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit) if (fpscr_ve) { goto raise_ve; } + break; case FPSCR_OX: env->fpscr |= 1 << FPSCR_FX; if (fpscr_oe) { From ea6c0dac4bf161bb696ef0867d94b6223e9432c0 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 30 May 2012 04:23:42 +0000 Subject: [PATCH 22/72] ppc: Make hbrev table const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lookup table 'hbrev' is never written to, so add a 'const' qualifier. Signed-off-by: Blue Swirl Signed-off-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/int_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 3173f11294..f638b2a07c 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -1484,7 +1484,7 @@ VUPK(lsh, s32, s16, UPKLO) /*****************************************************************************/ /* SPE extension helpers */ /* Use a table to make this quicker */ -static uint8_t hbrev[16] = { +static const uint8_t hbrev[16] = { 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE, 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF, }; From cba2026a410328216f26db276a6ecf0e55a06e17 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sat, 19 May 2012 00:48:50 +0200 Subject: [PATCH 23/72] PPC: mpc8544ds: Span initial TLB entry over as much RAM as we need The initial TLB entry is supposed to help us run the guest -kernel payload. This means the guest needs to be able to access its own memory, the initrd memory and the device tree. So far we only statically reserved a TLB entry from [0;256M[. This patch fixes it to span from [0;dt_end[, allowing the guest payload to access everything initially. Reported-by: Stuart Yoder Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 3eb8a23779..b1a0b8c542 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -31,6 +31,7 @@ #include "elf.h" #include "sysbus.h" #include "exec-memory.h" +#include "host-utils.h" #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" #define UIMAGE_LOAD_BASE 0 @@ -55,6 +56,7 @@ struct boot_info { uint32_t dt_base; + uint32_t dt_size; uint32_t entry; }; @@ -164,7 +166,11 @@ static int mpc8544_load_device_tree(CPUPPCState *env, } ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); + if (ret < 0) { + goto out; + } g_free(fdt); + ret = fdt_size; out: #endif @@ -172,23 +178,27 @@ out: return ret; } -/* Create -kernel TLB entries for BookE, linearly spanning 256MB. */ +/* Create -kernel TLB entries for BookE. */ static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size) { - return ffs(size >> 10) - 1; + return 63 - clz64(size >> 10); } -static void mmubooke_create_initial_mapping(CPUPPCState *env, - target_ulong va, - target_phys_addr_t pa) +static void mmubooke_create_initial_mapping(CPUPPCState *env) { + struct boot_info *bi = env->load_info; ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); - target_phys_addr_t size; + target_phys_addr_t size, dt_end; + int ps; - size = (booke206_page_size_to_tlb(256 * 1024 * 1024) << MAS1_TSIZE_SHIFT); + /* Our initial TLB entry needs to cover everything from 0 to + the device tree top */ + dt_end = bi->dt_base + bi->dt_size; + ps = booke206_page_size_to_tlb(dt_end) + 1; + size = (ps << MAS1_TSIZE_SHIFT); tlb->mas1 = MAS1_VALID | size; - tlb->mas2 = va & TARGET_PAGE_MASK; - tlb->mas7_3 = pa & TARGET_PAGE_MASK; + tlb->mas2 = 0; + tlb->mas7_3 = 0; tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; env->tlb_dirty = true; @@ -220,7 +230,7 @@ static void mpc8544ds_cpu_reset(void *opaque) env->gpr[1] = (16<<20) - 8; env->gpr[3] = bi->dt_base; env->nip = bi->entry; - mmubooke_create_initial_mapping(env, 0, 0); + mmubooke_create_initial_mapping(env); } static void mpc8544ds_init(ram_addr_t ram_size, @@ -379,13 +389,15 @@ static void mpc8544ds_init(ram_addr_t ram_size, /* If we're loading a kernel directly, we must load the device tree too. */ if (kernel_filename) { struct boot_info *boot_info; + int dt_size; #ifndef CONFIG_FDT cpu_abort(env, "Compiled without FDT support - can't load kernel\n"); #endif - dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; - if (mpc8544_load_device_tree(env, dt_base, ram_size, - initrd_base, initrd_size, kernel_cmdline) < 0) { + dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; + dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base, + initrd_size, kernel_cmdline); + if (dt_size < 0) { fprintf(stderr, "couldn't load device tree\n"); exit(1); } @@ -393,6 +405,7 @@ static void mpc8544ds_init(ram_addr_t ram_size, boot_info = env->load_info; boot_info->entry = entry; boot_info->dt_base = dt_base; + boot_info->dt_size = dt_size; } if (kvm_enabled()) { From c8f803e77a39584af30082b7ba11e69a9f046224 Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Mon, 14 May 2012 23:39:09 +0000 Subject: [PATCH 24/72] Avoid segfault in cpu_dump_state Do not call cpu_dump_state if logfile is NULL. Signed-off-by: Fabien Chouteau [agraf: adjust to inline functions] Signed-off-by: Alexander Graf --- qemu-log.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qemu-log.h b/qemu-log.h index 40f8b7b0c8..2ed19d1578 100644 --- a/qemu-log.h +++ b/qemu-log.h @@ -69,7 +69,9 @@ void GCC_FMT_ATTR(2, 3) qemu_log_mask(int mask, const char *fmt, ...); /* cpu_dump_state() logging functions: */ static inline void log_cpu_state(CPUArchState *env1, int flags) { - cpu_dump_state(env1, qemu_logfile, fprintf, flags); + if (qemu_log_enabled()) { + cpu_dump_state(env1, qemu_logfile, fprintf, flags); + } } static inline void log_cpu_state_mask(int mask, CPUArchState *env1, int flags) From 77c2cf33fe8d272e5375b55c588202a18af0e27c Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Mon, 21 May 2012 06:11:06 +0000 Subject: [PATCH 25/72] booke_206_tlbwe: Discard invalid bits in MAS2 The size of EPN field in MAS2 depends on page size. This patch adds a mask to discard invalid bits in EPN field. Definition of EPN field from e500v2 RM: EPN Effective page number: Depending on page size, only the bits associated with a page boundary are valid. Bits that represent offsets within a page are ignored and should be cleared. There is a similar (but more complicated) definition in PowerISA V2.06. Signed-off-by: Fabien Chouteau Signed-off-by: Alexander Graf --- target-ppc/mmu_helper.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index d65d2909b4..c4e79d9ca7 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -3019,6 +3019,8 @@ void helper_booke206_tlbwe(CPUPPCState *env) uint32_t tlbncfg, tlbn; ppcmas_tlb_t *tlb; uint32_t size_tlb, size_ps; + target_ulong mask; + switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) { case MAS0_WQ_ALWAYS: @@ -3081,8 +3083,19 @@ void helper_booke206_tlbwe(CPUPPCState *env) tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12; } - /* XXX needs to change when supporting 64-bit e500 */ - tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff; + /* Make a mask from TLB size to discard invalid bits in EPN field */ + mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); + /* Add a mask for page attributes */ + mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E; + + if (!msr_cm) { + /* Executing a tlbwe instruction in 32-bit mode will set + * bits 0:31 of the TLB EPN field to zero. + */ + mask &= 0xffffffff; + } + + tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask; if (!(tlbncfg & TLBnCFG_IPROT)) { /* no IPROT supported by TLB */ From 4656e1f01289cc3aa20986deb6a407165826abe5 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 18 Jun 2012 19:56:25 +0000 Subject: [PATCH 26/72] ppc64: Rudimentary Support for extra page sizes on server CPUs More recent Power server chips (i.e. based on the 64 bit hash MMU) support more than just the traditional 4k and 16M page sizes. This can get quite complicated, because which page sizes are supported, which combinations are supported within an MMU segment and how these page sizes are encoded both in the SLB entry and the hash PTE can vary depending on the CPU model (they are not specified by the architecture). In addition the firmware or hypervisor may not permit use of certain page sizes, for various reasons. Whether various page sizes are supported on KVM, for example, depends on whether the PR or HV variant of KVM is in use, and on the page size of the memory backing the guest's RAM. This patch adds information to the CPUState and cpu defs to describe the supported page sizes and encodings. Since TCG does not yet support any extended page sizes, we just set this to NULL in the static CPU definitions, expanding this to the default 4k and 16M page sizes when we initialize the cpu state. When using KVM, however, we instead determine available page sizes using the new KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use some defaults, with some guesswork which should do the right thing for existing HV and PR implementations. The fallback might not be correct for future versions, but that's ok, because they'll have KVM_PPC_GET_SMMU_INFO. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 31 ++++++ target-ppc/kvm.c | 208 ++++++++++++++++++++++++++++++++++++ target-ppc/kvm_ppc.h | 5 + target-ppc/mmu_helper.c | 7 ++ target-ppc/translate_init.c | 21 ++++ 5 files changed, 272 insertions(+) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 9b157f0246..67e699cdc9 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -119,6 +119,8 @@ enum powerpc_mmu_t { POWERPC_MMU_620 = POWERPC_MMU_64 | 0x00000002, /* Architecture 2.06 variant */ POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003, + /* Architecture 2.06 "degraded" (no 1T segments) */ + POWERPC_MMU_2_06d = POWERPC_MMU_64 | 0x00000003, #endif /* defined(TARGET_PPC64) */ }; @@ -873,6 +875,29 @@ enum { #define DBELL_LPIDTAG_MASK (0xfff << DBELL_LPIDTAG_SHIFT) #define DBELL_PIRTAG_MASK 0x3fff +/*****************************************************************************/ +/* Segment page size information, used by recent hash MMUs + * The format of this structure mirrors kvm_ppc_smmu_info + */ + +#define PPC_PAGE_SIZES_MAX_SZ 8 + +struct ppc_one_page_size { + uint32_t page_shift; /* Page shift (or 0) */ + uint32_t pte_enc; /* Encoding in the HPTE (>>12) */ +}; + +struct ppc_one_seg_page_size { + uint32_t page_shift; /* Base page shift of segment (or 0) */ + uint32_t slb_enc; /* SLB encoding for BookS */ + struct ppc_one_page_size enc[PPC_PAGE_SIZES_MAX_SZ]; +}; + +struct ppc_segment_page_sizes { + struct ppc_one_seg_page_size sps[PPC_PAGE_SIZES_MAX_SZ]; +}; + + /*****************************************************************************/ /* The whole PowerPC CPU context */ #define NB_MMU_MODES 3 @@ -889,6 +914,9 @@ struct ppc_def_t { powerpc_input_t bus_model; uint32_t flags; int bfd_mach; +#if defined(TARGET_PPC64) + const struct ppc_segment_page_sizes *sps; +#endif void (*init_proc)(CPUPPCState *env); int (*check_pow)(CPUPPCState *env); }; @@ -1012,6 +1040,9 @@ struct CPUPPCState { uint32_t flags; uint64_t insns_flags; uint64_t insns_flags2; +#if defined(TARGET_PPC64) + struct ppc_segment_page_sizes sps; +#endif #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) target_phys_addr_t vpa; diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index c09cc39c78..b6ef72d16b 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -167,10 +168,217 @@ static int kvm_booke206_tlb_init(CPUPPCState *env) return 0; } + +#if defined(TARGET_PPC64) +static void kvm_get_fallback_smmu_info(CPUPPCState *env, + struct kvm_ppc_smmu_info *info) +{ + memset(info, 0, sizeof(*info)); + + /* We don't have the new KVM_PPC_GET_SMMU_INFO ioctl, so + * need to "guess" what the supported page sizes are. + * + * For that to work we make a few assumptions: + * + * - If KVM_CAP_PPC_GET_PVINFO is supported we are running "PR" + * KVM which only supports 4K and 16M pages, but supports them + * regardless of the backing store characteritics. We also don't + * support 1T segments. + * + * This is safe as if HV KVM ever supports that capability or PR + * KVM grows supports for more page/segment sizes, those versions + * will have implemented KVM_CAP_PPC_GET_SMMU_INFO and thus we + * will not hit this fallback + * + * - Else we are running HV KVM. This means we only support page + * sizes that fit in the backing store. Additionally we only + * advertize 64K pages if the processor is ARCH 2.06 and we assume + * P7 encodings for the SLB and hash table. Here too, we assume + * support for any newer processor will mean a kernel that + * implements KVM_CAP_PPC_GET_SMMU_INFO and thus doesn't hit + * this fallback. + */ + if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_PVINFO)) { + /* No flags */ + info->flags = 0; + info->slb_size = 64; + + /* Standard 4k base page size segment */ + info->sps[0].page_shift = 12; + info->sps[0].slb_enc = 0; + info->sps[0].enc[0].page_shift = 12; + info->sps[0].enc[0].pte_enc = 0; + + /* Standard 16M large page size segment */ + info->sps[1].page_shift = 24; + info->sps[1].slb_enc = SLB_VSID_L; + info->sps[1].enc[0].page_shift = 24; + info->sps[1].enc[0].pte_enc = 0; + } else { + int i = 0; + + /* HV KVM has backing store size restrictions */ + info->flags = KVM_PPC_PAGE_SIZES_REAL; + + if (env->mmu_model & POWERPC_MMU_1TSEG) { + info->flags |= KVM_PPC_1T_SEGMENTS; + } + + if (env->mmu_model == POWERPC_MMU_2_06) { + info->slb_size = 32; + } else { + info->slb_size = 64; + } + + /* Standard 4k base page size segment */ + info->sps[i].page_shift = 12; + info->sps[i].slb_enc = 0; + info->sps[i].enc[0].page_shift = 12; + info->sps[i].enc[0].pte_enc = 0; + i++; + + /* 64K on MMU 2.06 */ + if (env->mmu_model == POWERPC_MMU_2_06) { + info->sps[i].page_shift = 16; + info->sps[i].slb_enc = 0x110; + info->sps[i].enc[0].page_shift = 16; + info->sps[i].enc[0].pte_enc = 1; + i++; + } + + /* Standard 16M large page size segment */ + info->sps[i].page_shift = 24; + info->sps[i].slb_enc = SLB_VSID_L; + info->sps[i].enc[0].page_shift = 24; + info->sps[i].enc[0].pte_enc = 0; + } +} + +static void kvm_get_smmu_info(CPUPPCState *env, struct kvm_ppc_smmu_info *info) +{ + int ret; + + if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_SMMU_INFO)) { + ret = kvm_vm_ioctl(env->kvm_state, KVM_PPC_GET_SMMU_INFO, info); + if (ret == 0) { + return; + } + } + + kvm_get_fallback_smmu_info(env, info); +} + +static long getrampagesize(void) +{ + struct statfs fs; + int ret; + + if (!mem_path) { + /* guest RAM is backed by normal anonymous pages */ + return getpagesize(); + } + + do { + ret = statfs(mem_path, &fs); + } while (ret != 0 && errno == EINTR); + + if (ret != 0) { + fprintf(stderr, "Couldn't statfs() memory path: %s\n", + strerror(errno)); + exit(1); + } + +#define HUGETLBFS_MAGIC 0x958458f6 + + if (fs.f_type != HUGETLBFS_MAGIC) { + /* Explicit mempath, but it's ordinary pages */ + return getpagesize(); + } + + /* It's hugepage, return the huge page size */ + return fs.f_bsize; +} + +static bool kvm_valid_page_size(uint32_t flags, long rampgsize, uint32_t shift) +{ + if (!(flags & KVM_PPC_PAGE_SIZES_REAL)) { + return true; + } + + return (1ul << shift) <= rampgsize; +} + +static void kvm_fixup_page_sizes(CPUPPCState *env) +{ + static struct kvm_ppc_smmu_info smmu_info; + static bool has_smmu_info; + long rampagesize; + int iq, ik, jq, jk; + + /* We only handle page sizes for 64-bit server guests for now */ + if (!(env->mmu_model & POWERPC_MMU_64)) { + return; + } + + /* Collect MMU info from kernel if not already */ + if (!has_smmu_info) { + kvm_get_smmu_info(env, &smmu_info); + has_smmu_info = true; + } + + rampagesize = getrampagesize(); + + /* Convert to QEMU form */ + memset(&env->sps, 0, sizeof(env->sps)); + + for (ik = iq = 0; ik < KVM_PPC_PAGE_SIZES_MAX_SZ; ik++) { + struct ppc_one_seg_page_size *qsps = &env->sps.sps[iq]; + struct kvm_ppc_one_seg_page_size *ksps = &smmu_info.sps[ik]; + + if (!kvm_valid_page_size(smmu_info.flags, rampagesize, + ksps->page_shift)) { + continue; + } + qsps->page_shift = ksps->page_shift; + qsps->slb_enc = ksps->slb_enc; + for (jk = jq = 0; jk < KVM_PPC_PAGE_SIZES_MAX_SZ; jk++) { + if (!kvm_valid_page_size(smmu_info.flags, rampagesize, + ksps->enc[jk].page_shift)) { + continue; + } + qsps->enc[jq].page_shift = ksps->enc[jk].page_shift; + qsps->enc[jq].pte_enc = ksps->enc[jk].pte_enc; + if (++jq >= PPC_PAGE_SIZES_MAX_SZ) { + break; + } + } + if (++iq >= PPC_PAGE_SIZES_MAX_SZ) { + break; + } + } + env->slb_nr = smmu_info.slb_size; + if (smmu_info.flags & KVM_PPC_1T_SEGMENTS) { + env->mmu_model |= POWERPC_MMU_1TSEG; + } else { + env->mmu_model &= ~POWERPC_MMU_1TSEG; + } +} +#else /* defined (TARGET_PPC64) */ + +static inline void kvm_fixup_page_sizes(CPUPPCState *env) +{ +} + +#endif /* !defined (TARGET_PPC64) */ + int kvm_arch_init_vcpu(CPUPPCState *cenv) { int ret; + /* Gather server mmu info from KVM and update the CPU state */ + kvm_fixup_page_sizes(cenv); + + /* Synchronize sregs with kvm */ ret = kvm_arch_sync_sregs(cenv); if (ret) { return ret; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 34ecad3e26..e2f8703853 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -58,6 +58,11 @@ static inline int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_l return -1; } +static inline int kvmppc_read_segment_page_sizes(uint32_t *prop, int maxcells) +{ + return -1; +} + static inline int kvmppc_set_interrupt(CPUPPCState *env, int irq, int level) { return -1; diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index c4e79d9ca7..d2664acef0 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -1634,6 +1634,7 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env) #if defined(TARGET_PPC64) case POWERPC_MMU_64B: case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06d: mmubooks_dump_mmu(f, cpu_fprintf, env); break; #endif @@ -1664,6 +1665,7 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, case POWERPC_MMU_620: case POWERPC_MMU_64B: case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06d: /* Real address are 60 bits long */ ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL; ctx->prot |= PAGE_WRITE; @@ -1745,6 +1747,7 @@ int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr, case POWERPC_MMU_620: case POWERPC_MMU_64B: case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06d: #endif if (ret < 0) { /* We didn't match any BAT entry or don't have BATs */ @@ -1886,6 +1889,7 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, case POWERPC_MMU_620: case POWERPC_MMU_64B: case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06d: #endif env->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x40000000; @@ -1997,6 +2001,7 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, case POWERPC_MMU_620: case POWERPC_MMU_64B: case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06d: #endif env->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; @@ -2326,6 +2331,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env) case POWERPC_MMU_620: case POWERPC_MMU_64B: case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06d: #endif /* defined(TARGET_PPC64) */ tlb_flush(env, 1); break; @@ -2395,6 +2401,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) case POWERPC_MMU_620: case POWERPC_MMU_64B: case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06d: /* tlbie invalidate TLBs for all segments */ /* XXX: given the fact that there are too many segments to invalidate, * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU, diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f6ac589a53..57027a2883 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9928,6 +9928,27 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) env->bfd_mach = def->bfd_mach; env->check_pow = def->check_pow; +#if defined(TARGET_PPC64) + if (def->sps) + env->sps = *def->sps; + else if (env->mmu_model & POWERPC_MMU_64) { + /* Use default sets of page sizes */ + static const struct ppc_segment_page_sizes defsps = { + .sps = { + { .page_shift = 12, /* 4K */ + .slb_enc = 0, + .enc = { { .page_shift = 12, .pte_enc = 0 } } + }, + { .page_shift = 24, /* 16M */ + .slb_enc = 0x100, + .enc = { { .page_shift = 24, .pte_enc = 0 } } + }, + }, + }; + env->sps = defsps; + } +#endif /* defined(TARGET_PPC64) */ + if (kvm_enabled()) { if (kvmppc_fixup_cpu(env) != 0) { fprintf(stderr, "Unable to virtualize selected CPU with KVM\n"); From 5af9873d301cf5affec57e2f93650e8700f8251a Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 18 Jun 2012 19:56:30 +0000 Subject: [PATCH 27/72] pseries: Correctly create ibm,segment-page-sizes property The core tcg/kvm code for ppc64 now has at least the outline capability to support pagesizes beyond the standard 4k and 16MB. The CPUState is initialized with information advertising the available pagesizes and their correct encodings, and under the right KVM setup this will be populated with page sizes beyond the standard. Obviously guests can't use the extra page sizes unless they know they're present. For the pseries machine, at least, there is a defined method for conveying exactly this information, the "ibm-segment-page-sizes" property in the guest device tree. This patch generates this property using the supported page size information that's already in the CPUState. Signed-off-by: Nishanth Aravamudan Signed-off-by: David Gibson Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Alexander Graf --- hw/spapr.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/hw/spapr.c b/hw/spapr.c index d0bddbce95..1b01d6475d 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -146,6 +146,40 @@ static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr) return ret; } + +static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, + size_t maxsize) +{ + size_t maxcells = maxsize / sizeof(uint32_t); + int i, j, count; + uint32_t *p = prop; + + for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) { + struct ppc_one_seg_page_size *sps = &env->sps.sps[i]; + + if (!sps->page_shift) { + break; + } + for (count = 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) { + if (sps->enc[count].page_shift == 0) { + break; + } + } + if ((p - prop) >= (maxcells - 3 - count * 2)) { + break; + } + *(p++) = cpu_to_be32(sps->page_shift); + *(p++) = cpu_to_be32(sps->slb_enc); + *(p++) = cpu_to_be32(count); + for (j = 0; j < count; j++) { + *(p++) = cpu_to_be32(sps->enc[j].page_shift); + *(p++) = cpu_to_be32(sps->enc[j].pte_enc); + } + } + + return (p - prop) * sizeof(uint32_t); +} + static void *spapr_create_fdt_skel(const char *cpu_model, target_phys_addr_t rma_size, target_phys_addr_t initrd_base, @@ -298,6 +332,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model, 0xffffffff, 0xffffffff}; uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ; uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000; + uint32_t page_sizes_prop[64]; + size_t page_sizes_prop_size; if ((index % smt) != 0) { continue; @@ -362,6 +398,13 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property_cell(fdt, "ibm,dfp", 1))); } + page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop, + sizeof(page_sizes_prop)); + if (page_sizes_prop_size) { + _FDT((fdt_property(fdt, "ibm,segment-page-sizes", + page_sizes_prop, page_sizes_prop_size))); + } + _FDT((fdt_end_node(fdt))); } From a4d8e8daee324e230b0155915f562743f4fff5d8 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 18 Jun 2012 20:02:38 +0000 Subject: [PATCH 28/72] spapr_vscsi: Error handling fixes We were incorrectly g_free'ing an object that isn't allocated in one error path and failed to release it completely in another This fixes qemu crashes with some cases of IO errors. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Alexander Graf --- hw/spapr_vscsi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 037867ab4f..2f09616dd5 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -800,6 +800,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq) if (crq->s.IU_length > sizeof(union viosrp_iu)) { fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n", crq->s.IU_length); + vscsi_put_req(req); return; } @@ -807,7 +808,8 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq) if (spapr_tce_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu, crq->s.IU_length)) { fprintf(stderr, "vscsi_got_payload: DMA read failure !\n"); - g_free(req); + vscsi_put_req(req); + return; } memcpy(&req->crq, crq, sizeof(vscsi_crq)); From c73e3771ea79ab3898da3ba51ff6fc5b05948d85 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 18 Jun 2012 20:21:37 +0000 Subject: [PATCH 29/72] spapr: Add "memop" hypercall This adds a qemu-specific hypervisor call to the pseries machine which allows to do what amounts to memmove, memcpy and xor over regions of physical memory such as the framebuffer. This is the simplest way to get usable framebuffer speed from SLOF since the framebuffer isn't mapped in the VRMA and so would otherwise require an hcall per 8 bytes access. The performance is still not great but usable, and can be improved with a more complex implementation of the hcall itself if needed. This also adds some documentation for the qemu-specific hypercalls that we add to PAPR along with a new qemu,hypertas-functions property that mirrors ibm,hypertas-functions and provides some discoverability for the new calls. Note: I chose note to advertise H_RTAS to the guest via that mechanism. This is done on purpose, the guest uses the normal RTAS interfaces provided by qemu (including SLOF) which internally calls H_RTAS. We might in the future implement part (or even all) of RTAS inside the guest like IBM's firmware does and replace H_RTAS with some finer grained set of private hypercalls. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Alexander Graf --- docs/specs/ppc-spapr-hcalls.txt | 78 +++++++++++++++++++++++++++++++++ hw/spapr.c | 3 ++ hw/spapr.h | 3 +- hw/spapr_hcall.c | 68 ++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 docs/specs/ppc-spapr-hcalls.txt diff --git a/docs/specs/ppc-spapr-hcalls.txt b/docs/specs/ppc-spapr-hcalls.txt new file mode 100644 index 0000000000..52ba8d42ab --- /dev/null +++ b/docs/specs/ppc-spapr-hcalls.txt @@ -0,0 +1,78 @@ +When used with the "pseries" machine type, QEMU-system-ppc64 implements +a set of hypervisor calls using a subset of the server "PAPR" specification +(IBM internal at this point), which is also what IBM's proprietary hypervisor +adheres too. + +The subset is selected based on the requirements of Linux as a guest. + +In addition to those calls, we have added our own private hypervisor +calls which are mostly used as a private interface between the firmware +running in the guest and QEMU. + +All those hypercalls start at hcall number 0xf000 which correspond +to a implementation specific range in PAPR. + +- H_RTAS (0xf000) + +RTAS is a set of runtime services generally provided by the firmware +inside the guest to the operating system. It predates the existence +of hypervisors (it was originally an extension to Open Firmware) and +is still used by PAPR to provide various services that aren't performance +sensitive. + +We currently implement the RTAS services in QEMU itself. The actual RTAS +"firmware" blob in the guest is a small stub of a few instructions which +calls our private H_RTAS hypervisor call to pass the RTAS calls to QEMU. + +Arguments: + + r3 : H_RTAS (0xf000) + r4 : Guest physical address of RTAS parameter block + +Returns: + + H_SUCCESS : Successully called the RTAS function (RTAS result + will have been stored in the parameter block) + H_PARAMETER : Unknown token + +- H_LOGICAL_MEMOP (0xf001) + +When the guest runs in "real mode" (in powerpc lingua this means +with MMU disabled, ie guest effective == guest physical), it only +has access to a subset of memory and no IOs. + +PAPR provides a set of hypervisor calls to perform cachable or +non-cachable accesses to any guest physical addresses that the +guest can use in order to access IO devices while in real mode. + +This is typically used by the firmware running in the guest. + +However, doing a hypercall for each access is extremely inefficient +(even more so when running KVM) when accessing the frame buffer. In +that case, things like scrolling become unusably slow. + +This hypercall allows the guest to request a "memory op" to be applied +to memory. The supported memory ops at this point are to copy a range +of memory (supports overlap of source and destination) and XOR which +is used by our SLOF firmware to invert the screen. + +Arguments: + + r3: H_LOGICAL_MEMOP (0xf001) + r4: Guest physical address of destination + r5: Guest physical address of source + r6: Individual element size + 0 = 1 byte + 1 = 2 bytes + 2 = 4 bytes + 3 = 8 bytes + r7: Number of elements + r8: Operation + 0 = copy + 1 = xor + +Returns: + + H_SUCCESS : Success + H_PARAMETER : Invalid argument + diff --git a/hw/spapr.c b/hw/spapr.c index 1b01d6475d..09a23ff092 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -197,6 +197,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk"; + char qemu_hypertas_prop[] = "hcall-memop1"; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; int i; char *modelname; @@ -417,6 +418,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop, sizeof(hypertas_prop)))); + _FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas_prop, + sizeof(qemu_hypertas_prop)))); _FDT((fdt_property(fdt, "ibm,associativity-reference-points", refpoints, sizeof(refpoints)))); diff --git a/hw/spapr.h b/hw/spapr.h index 654a7a8a34..c75172e0c0 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -264,7 +264,8 @@ typedef struct sPAPREnvironment { */ #define KVMPPC_HCALL_BASE 0xf000 #define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0) -#define KVMPPC_HCALL_MAX KVMPPC_H_RTAS +#define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1) +#define KVMPPC_HCALL_MAX KVMPPC_H_LOGICAL_MEMOP extern sPAPREnvironment *spapr; diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index 94bb504ca6..a5990a9617 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -608,6 +608,73 @@ static target_ulong h_logical_store(CPUPPCState *env, sPAPREnvironment *spapr, return H_PARAMETER; } +static target_ulong h_logical_memop(CPUPPCState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong dst = args[0]; /* Destination address */ + target_ulong src = args[1]; /* Source address */ + target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */ + target_ulong count = args[3]; /* Element count */ + target_ulong op = args[4]; /* 0 = copy, 1 = invert */ + uint64_t tmp; + unsigned int mask = (1 << esize) - 1; + int step = 1 << esize; + + if (count > 0x80000000) { + return H_PARAMETER; + } + + if ((dst & mask) || (src & mask) || (op > 1)) { + return H_PARAMETER; + } + + if (dst >= src && dst < (src + (count << esize))) { + dst = dst + ((count - 1) << esize); + src = src + ((count - 1) << esize); + step = -step; + } + + while (count--) { + switch (esize) { + case 0: + tmp = ldub_phys(src); + break; + case 1: + tmp = lduw_phys(src); + break; + case 2: + tmp = ldl_phys(src); + break; + case 3: + tmp = ldq_phys(src); + break; + default: + return H_PARAMETER; + } + if (op == 1) { + tmp = ~tmp; + } + switch (esize) { + case 0: + stb_phys(dst, tmp); + break; + case 1: + stw_phys(dst, tmp); + break; + case 2: + stl_phys(dst, tmp); + break; + case 3: + stq_phys(dst, tmp); + break; + } + dst = dst + step; + src = src + step; + } + + return H_SUCCESS; +} + static target_ulong h_logical_icbi(CPUPPCState *env, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -700,6 +767,7 @@ static void hypercall_register_types(void) spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store); spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi); spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf); + spapr_register_hypercall(KVMPPC_H_LOGICAL_MEMOP, h_logical_memop); /* qemu/KVM-PPC specific hcalls */ spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas); From 94282e714628ee4b130b46f3b06b34da45b2fe6a Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 19 Jun 2012 22:02:51 +0000 Subject: [PATCH 30/72] raw-posix: Fix build without is_allocated support Move the declaration of s into the #ifdef sections that actually make use of it. Signed-off-by: Kevin Wolf Signed-off-by: Alexander Graf --- block/raw-posix.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index bf7700a238..0dce089be5 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -606,7 +606,6 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { - BDRVRawState *s = bs->opaque; off_t start, data, hole; int ret; @@ -616,11 +615,15 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs, } start = sector_num * BDRV_SECTOR_SIZE; + #ifdef CONFIG_FIEMAP + + BDRVRawState *s = bs->opaque; struct { struct fiemap fm; struct fiemap_extent fe; } f; + f.fm.fm_start = start; f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE; f.fm.fm_flags = 0; @@ -643,7 +646,11 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs, data = f.fe.fe_logical; hole = f.fe.fe_logical + f.fe.fe_length; } + #elif defined SEEK_HOLE && defined SEEK_DATA + + BDRVRawState *s = bs->opaque; + hole = lseek(s->fd, start, SEEK_HOLE); if (hole == -1) { /* -ENXIO indicates that sector_num was past the end of the file. From c640d088349acaf23161e7afb3dfeb5d6a7007f1 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 11:40:42 +0200 Subject: [PATCH 31/72] dt: allow add_subnode to create root subnodes Our subnode creation helper can't handle creation of root subnodes, like "/memory". Fix this by allowing the parent node to be an empty string, indicating the root node. Signed-off-by: Alexander Graf Reviewed-by: Peter Crosthwaite --- device_tree.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/device_tree.c b/device_tree.c index 86a694c955..94a239e987 100644 --- a/device_tree.c +++ b/device_tree.c @@ -151,6 +151,7 @@ int qemu_devtree_add_subnode(void *fdt, const char *name) char *dupname = g_strdup(name); char *basename = strrchr(dupname, '/'); int retval; + int parent = 0; if (!basename) { g_free(dupname); @@ -160,7 +161,11 @@ int qemu_devtree_add_subnode(void *fdt, const char *name) basename[0] = '\0'; basename++; - retval = fdt_add_subnode(fdt, findnode_nofail(fdt, dupname), basename); + if (dupname[0]) { + parent = findnode_nofail(fdt, dupname); + } + + retval = fdt_add_subnode(fdt, parent, basename); if (retval < 0) { fprintf(stderr, "FDT: Failed to create subnode %s: %s\n", name, fdt_strerror(retval)); From 7ae2291e8e0f34ac520044c8af0437a701e1c967 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 12:47:57 +0200 Subject: [PATCH 32/72] dt: add helpers for multi-cell adds We have device tree helpers that allow us to create single cell (u32) wide properties. However, when creating properties that contain an array of cells, we need to jump through hoops, manually passing in an array with converted endianness. To ease the pain of this, create a generic macro helper that allows us to pass the cells as arguments. Signed-off-by: Alexander Graf Reviewed-by: Peter Crosthwaite --- device_tree.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/device_tree.h b/device_tree.h index 4378685b7a..1e671e2506 100644 --- a/device_tree.h +++ b/device_tree.h @@ -25,4 +25,16 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path, int qemu_devtree_nop_node(void *fdt, const char *node_path); int qemu_devtree_add_subnode(void *fdt, const char *name); +#define qemu_devtree_setprop_cells(fdt, node_path, property, ...) \ + do { \ + uint32_t qdt_tmp[] = { __VA_ARGS__ }; \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(qdt_tmp); i++) { \ + qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); \ + } \ + qemu_devtree_setprop(fdt, node_path, property, qdt_tmp, \ + sizeof(qdt_tmp)); \ + } while (0) + #endif /* __DEVICE_TREE_H__ */ From 8535ab125853d1ba9067ba408c532c2ad79146e6 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 14:11:52 +0200 Subject: [PATCH 33/72] dt: add helper for phandle references Phandles are the fancy device tree name for "pointer to another node". To create a phandle property, we most likely want to reference to the node we're pointing to by its path. So create a helper that allows us to do so. Signed-off-by: Alexander Graf Reviewed-by: Peter Crosthwaite --- device_tree.c | 8 ++++++++ device_tree.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/device_tree.c b/device_tree.c index 94a239e987..2905f9afe4 100644 --- a/device_tree.c +++ b/device_tree.c @@ -132,6 +132,14 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path, return r; } +int qemu_devtree_setprop_phandle(void *fdt, const char *node_path, + const char *property, + const char *target_node_path) +{ + uint32_t phandle = fdt_get_phandle(fdt, findnode_nofail(fdt, target_node_path)); + return qemu_devtree_setprop_cell(fdt, node_path, property, phandle); +} + int qemu_devtree_nop_node(void *fdt, const char *node_path) { int r; diff --git a/device_tree.h b/device_tree.h index 1e671e2506..754bd2b2ec 100644 --- a/device_tree.h +++ b/device_tree.h @@ -22,6 +22,9 @@ int qemu_devtree_setprop_cell(void *fdt, const char *node_path, const char *property, uint32_t val); int qemu_devtree_setprop_string(void *fdt, const char *node_path, const char *property, const char *string); +int qemu_devtree_setprop_phandle(void *fdt, const char *node_path, + const char *property, + const char *target_node_path); int qemu_devtree_nop_node(void *fdt, const char *node_path); int qemu_devtree_add_subnode(void *fdt, const char *name); From ef5d833fc6f04119ded9fca294d26ce225d69490 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 14:12:57 +0200 Subject: [PATCH 34/72] dt: temporarily disable subtree creation failure check Usually we want to know when creating a subtree fails. However, while introducing this patch set we have to modify the device tree and some times have the code to create a subtree in both the binary tree and the dynamically created tree. So ignore failures about this for now and enable them once we got rid of the binary device tree. Signed-off-by: Alexander Graf --- device_tree.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/device_tree.c b/device_tree.c index 2905f9afe4..967c97ac04 100644 --- a/device_tree.c +++ b/device_tree.c @@ -174,11 +174,13 @@ int qemu_devtree_add_subnode(void *fdt, const char *name) } retval = fdt_add_subnode(fdt, parent, basename); +#if 0 if (retval < 0) { fprintf(stderr, "FDT: Failed to create subnode %s: %s\n", name, fdt_strerror(retval)); exit(1); } +#endif g_free(dupname); return retval; From 7d5fd1089c36391ffc53a694101f441ab8cbbc05 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 15:23:39 +0200 Subject: [PATCH 35/72] dt: add helper for phandle enumeration This patch adds a helper to search for a node's phandle by its path. This is especially useful when the phandle is part of an array, not just a single cell in which case qemu_devtree_setprop_phandle would be the easy choice. Signed-off-by: Alexander Graf Reviewed-by: Peter Crosthwaite --- device_tree.c | 16 +++++++++++++++- device_tree.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/device_tree.c b/device_tree.c index 967c97ac04..2f127b71b0 100644 --- a/device_tree.c +++ b/device_tree.c @@ -132,11 +132,25 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path, return r; } +uint32_t qemu_devtree_get_phandle(void *fdt, const char *path) +{ + uint32_t r; + + r = fdt_get_phandle(fdt, findnode_nofail(fdt, path)); + if (r <= 0) { + fprintf(stderr, "%s: Couldn't get phandle for %s: %s\n", __func__, + path, fdt_strerror(r)); + exit(1); + } + + return r; +} + int qemu_devtree_setprop_phandle(void *fdt, const char *node_path, const char *property, const char *target_node_path) { - uint32_t phandle = fdt_get_phandle(fdt, findnode_nofail(fdt, target_node_path)); + uint32_t phandle = qemu_devtree_get_phandle(fdt, target_node_path); return qemu_devtree_setprop_cell(fdt, node_path, property, phandle); } diff --git a/device_tree.h b/device_tree.h index 754bd2b2ec..36fc9dbede 100644 --- a/device_tree.h +++ b/device_tree.h @@ -25,6 +25,7 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path, int qemu_devtree_setprop_phandle(void *fdt, const char *node_path, const char *property, const char *target_node_path); +uint32_t qemu_devtree_get_phandle(void *fdt, const char *path); int qemu_devtree_nop_node(void *fdt, const char *node_path); int qemu_devtree_add_subnode(void *fdt, const char *name); From ce36252cc1711a5e222ed68e72235088aec2529d Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 15:33:54 +0200 Subject: [PATCH 36/72] dt: add helper for empty dt creation We want to get rid of the concept of loading an external device tree and instead generate our own. However, to do this we need to also create a device tree template programatically. This patch adds a helper to create an empty device tree in memory. Signed-off-by: Alexander Graf Reviewed-by: Peter Crosthwaite --- device_tree.c | 37 +++++++++++++++++++++++++++++++++++++ device_tree.h | 1 + 2 files changed, 38 insertions(+) diff --git a/device_tree.c b/device_tree.c index 2f127b71b0..d0378961f0 100644 --- a/device_tree.c +++ b/device_tree.c @@ -25,6 +25,43 @@ #include +#define FDT_MAX_SIZE 0x10000 + +void *create_device_tree(int *sizep) +{ + void *fdt; + int ret; + + *sizep = FDT_MAX_SIZE; + fdt = g_malloc0(FDT_MAX_SIZE); + ret = fdt_create(fdt, FDT_MAX_SIZE); + if (ret < 0) { + goto fail; + } + ret = fdt_begin_node(fdt, ""); + if (ret < 0) { + goto fail; + } + ret = fdt_end_node(fdt); + if (ret < 0) { + goto fail; + } + ret = fdt_finish(fdt); + if (ret < 0) { + goto fail; + } + ret = fdt_open_into(fdt, fdt, *sizep); + if (ret) { + fprintf(stderr, "Unable to copy device tree in memory\n"); + exit(1); + } + + return fdt; +fail: + fprintf(stderr, "%s Couldn't create dt: %s\n", __func__, fdt_strerror(ret)); + exit(1); +} + void *load_device_tree(const char *filename_path, int *sizep) { int dt_size; diff --git a/device_tree.h b/device_tree.h index 36fc9dbede..5f76f40eeb 100644 --- a/device_tree.h +++ b/device_tree.h @@ -14,6 +14,7 @@ #ifndef __DEVICE_TREE_H__ #define __DEVICE_TREE_H__ +void *create_device_tree(int *sizep); void *load_device_tree(const char *filename_path, int *sizep); int qemu_devtree_setprop(void *fdt, const char *node_path, From 3601b572820ee5f3676ab24c068a4e011b72236d Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 16:58:55 +0200 Subject: [PATCH 37/72] dt: add helper for phandle allocation Phandle references work by having 2 pieces: - a "phandle" 1-cell property in the device tree node - a reference to the same value in a property we want to point to the other node To generate the 1-cell property, we need an allocation mechanism that gives us a unique number space. This patch adds an allocator for these properties. Signed-off-by: Alexander Graf --- device_tree.c | 7 +++++++ device_tree.h | 1 + 2 files changed, 8 insertions(+) diff --git a/device_tree.c b/device_tree.c index d0378961f0..75412747b7 100644 --- a/device_tree.c +++ b/device_tree.c @@ -191,6 +191,13 @@ int qemu_devtree_setprop_phandle(void *fdt, const char *node_path, return qemu_devtree_setprop_cell(fdt, node_path, property, phandle); } +uint32_t qemu_devtree_alloc_phandle(void *fdt) +{ + static int phandle = 0x8000; + + return phandle++; +} + int qemu_devtree_nop_node(void *fdt, const char *node_path) { int r; diff --git a/device_tree.h b/device_tree.h index 5f76f40eeb..97af3454f7 100644 --- a/device_tree.h +++ b/device_tree.h @@ -27,6 +27,7 @@ int qemu_devtree_setprop_phandle(void *fdt, const char *node_path, const char *property, const char *target_node_path); uint32_t qemu_devtree_get_phandle(void *fdt, const char *path); +uint32_t qemu_devtree_alloc_phandle(void *fdt); int qemu_devtree_nop_node(void *fdt, const char *node_path); int qemu_devtree_add_subnode(void *fdt, const char *name); From bb28eb3797b0fbb4baa6d87edf69b3a0ff499e94 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 May 2012 01:53:01 +0200 Subject: [PATCH 38/72] dt: add helper for 64bit cell adds Some times in the device tree, we find an array of 2 u32 cells that really are a single u64 value. This patch adds a helper to make the creation of these easy. Signed-off-by: Alexander Graf Reviewed-by: Peter Crosthwaite --- device_tree.c | 7 +++++++ device_tree.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/device_tree.c b/device_tree.c index 75412747b7..c8d68c203e 100644 --- a/device_tree.c +++ b/device_tree.c @@ -154,6 +154,13 @@ int qemu_devtree_setprop_cell(void *fdt, const char *node_path, return r; } +int qemu_devtree_setprop_u64(void *fdt, const char *node_path, + const char *property, uint64_t val) +{ + val = cpu_to_be64(val); + return qemu_devtree_setprop(fdt, node_path, property, &val, sizeof(val)); +} + int qemu_devtree_setprop_string(void *fdt, const char *node_path, const char *property, const char *string) { diff --git a/device_tree.h b/device_tree.h index 97af3454f7..4898d957af 100644 --- a/device_tree.h +++ b/device_tree.h @@ -21,6 +21,8 @@ int qemu_devtree_setprop(void *fdt, const char *node_path, const char *property, void *val_array, int size); int qemu_devtree_setprop_cell(void *fdt, const char *node_path, const char *property, uint32_t val); +int qemu_devtree_setprop_u64(void *fdt, const char *node_path, + const char *property, uint64_t val); int qemu_devtree_setprop_string(void *fdt, const char *node_path, const char *property, const char *string); int qemu_devtree_setprop_phandle(void *fdt, const char *node_path, From 63397dd0be8d03d62393620e8192dafe0db72f8f Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 12:23:41 +0200 Subject: [PATCH 39/72] PPC: e500: require libfdt Now that we're moving all of the device tree generation from an external pre-execution generated blob to runtime generation using libfdt, we absolutely must have libfdt around. This requirement was there before already, as the only way to not require libfdt with e500 was to not use -kernel, which was the only way to boot the mpc8544ds machine. This patch only manifests said requirement in the build system. Signed-off-by: Alexander Graf --- hw/ppc/Makefile.objs | 2 +- hw/ppce500_mpc8544ds.c | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 44a1e8cdab..d18dbaf6cc 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -15,7 +15,7 @@ obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o obj-y += ppc440_bamboo.o # PowerPC E500 boards -obj-y += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o +obj-$(CONFIG_FDT) += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o # PowerPC 440 Xilinx ML507 reference board. obj-y += virtex_ml507.o # PowerPC OpenPIC diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index b1a0b8c542..506ddf38b8 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -68,7 +68,6 @@ static int mpc8544_load_device_tree(CPUPPCState *env, const char *kernel_cmdline) { int ret = -1; -#ifdef CONFIG_FDT uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)}; char *filename; int fdt_size; @@ -173,7 +172,6 @@ static int mpc8544_load_device_tree(CPUPPCState *env, ret = fdt_size; out: -#endif return ret; } @@ -391,9 +389,6 @@ static void mpc8544ds_init(ram_addr_t ram_size, struct boot_info *boot_info; int dt_size; -#ifndef CONFIG_FDT - cpu_abort(env, "Compiled without FDT support - can't load kernel\n"); -#endif dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base, initrd_size, kernel_cmdline); From dd0bcfca64d12f557fae67a0ca318bf9b5579dd9 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 11:34:50 +0200 Subject: [PATCH 40/72] PPC: e500: dt: create memory node dynamically Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 8 ++++---- pc-bios/mpc8544ds.dtb | Bin 2028 -> 1972 bytes pc-bios/mpc8544ds.dts | 5 ----- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 506ddf38b8..3ec90133fd 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -88,10 +88,10 @@ static int mpc8544_load_device_tree(CPUPPCState *env, } /* Manipulate device tree in memory. */ - ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, - sizeof(mem_reg_property)); - if (ret < 0) - fprintf(stderr, "couldn't set /memory/reg\n"); + qemu_devtree_add_subnode(fdt, "/memory"); + qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory"); + qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, + sizeof(mem_reg_property)); if (initrd_size) { ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb index c6d302153c7407d5d0127be29b0c35f80e47f8fb..db9fb701f246e058bca4c2fe9546c9f2493a57b1 100644 GIT binary patch delta 104 zcmaFEzlC4m0`I@K3=HgB7#J8V7#P@QOcW4jOxUQQ!8o~tF`dzO@&`t7#*oPzOxY|U z3=FQ5xtSd&?_lx=2{E?=$qCHM8ACQ(uxw`psb#GO3gxhE;!Mm-Pc3FBN==`v&VCdC D8)_c+ delta 159 zcmdnO|At@S0`I@K3=HgV7#J8V7#P?tOcW4joUu_ugHb0pH8;Pg5-85VzzoFfK; }; - memory { - device_type = "memory"; - reg = <0x0 0x0>; // Filled by U-Boot - }; - soc8544@e0000000 { #address-cells = <1>; #size-cells = <1>; From 625e665b61184cabce0d556910de05cc8a70169c Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 11:48:16 +0200 Subject: [PATCH 41/72] PPC: e500: dt: create /cpus node dynamically Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 5 +++++ pc-bios/mpc8544ds.dtb | Bin 1972 -> 1924 bytes pc-bios/mpc8544ds.dts | 5 ----- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 3ec90133fd..c046206e16 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -125,6 +125,11 @@ static int mpc8544_load_device_tree(CPUPPCState *env, hypercall, sizeof(hypercall)); } + /* Create CPU nodes */ + qemu_devtree_add_subnode(fdt, "/cpus"); + qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1); + qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0); + /* We need to generate the cpu nodes in reverse order, so Linux can pick the first node as boot node and be happy */ for (i = smp_cpus - 1; i >= 0; i--) { diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb index db9fb701f246e058bca4c2fe9546c9f2493a57b1..a85b93c1e6e66c318c3f0c1910abae78f4b78f5e 100644 GIT binary patch delta 34 qcmdnO-@-3&f%o5A1_t&P1_lNT1_ri_i2~w`1`{=YYz|;dVFLiG$q8rx delta 43 zcmZqS-@-3&f%o5A1_t&m3=9kw3=C{DCJKl%CQQ`$!IE51T0Gf+QF*gCV=fy28+Z(E diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts index f46e9ede06..1fcb8658fd 100644 --- a/pc-bios/mpc8544ds.dts +++ b/pc-bios/mpc8544ds.dts @@ -22,11 +22,6 @@ pci0 = &pci0; }; - cpus { - #address-cells = <1>; - #size-cells = <0>; - }; - soc8544@e0000000 { #address-cells = <1>; #size-cells = <1>; From d50f71a5fda5515021a33e8e391decb5602f6328 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 11:50:05 +0200 Subject: [PATCH 42/72] PPC: e500: dt: create /hypervisor node dynamically Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 1 + pc-bios/mpc8544ds.dtb | Bin 1924 -> 1904 bytes pc-bios/mpc8544ds.dts | 3 --- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index c046206e16..54e7ec7c20 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -118,6 +118,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, tb_freq = kvmppc_get_tbfreq(); /* indicate KVM hypercall interface */ + qemu_devtree_add_subnode(fdt, "/hypervisor"); qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible", "linux,kvm"); kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb index a85b93c1e6e66c318c3f0c1910abae78f4b78f5e..8194aa2e6f292fb34023feb596aa19448b8af0d0 100644 GIT binary patch delta 35 rcmZqS|G+13f%o5A1_t&51_lNT1_ri}i2~w`G8;A2*)}J$DKY{8vYZHv delta 47 zcmeys*TOGwf%o5A1_t&P1_lNT1_ri_i2~w`1{*ch*|-@qDhpDJ$})@di#EHlX)yu- DKg10i diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts index 1fcb8658fd..2ca7c5421e 100644 --- a/pc-bios/mpc8544ds.dts +++ b/pc-bios/mpc8544ds.dts @@ -103,7 +103,4 @@ chosen { linux,stdout-path = "/soc8544@e0000000/serial@4500"; }; - - hypervisor { - }; }; From 51b852b74c999f099338fba1b26bbbb4ab8a0bd4 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 12:20:50 +0200 Subject: [PATCH 43/72] PPC: e500: dt: create / node dynamically Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 8 ++++++++ pc-bios/mpc8544ds.dtb | Bin 1904 -> 1810 bytes pc-bios/mpc8544ds.dts | 5 ----- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 54e7ec7c20..28c7c8c93d 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -76,6 +76,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env, uint32_t clock_freq = 400000000; uint32_t tb_freq = 400000000; int i; + char compatible[] = "MPC8544DS\0MPC85xxDS"; + char model[] = "MPC8544DS"; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { @@ -88,6 +90,12 @@ static int mpc8544_load_device_tree(CPUPPCState *env, } /* Manipulate device tree in memory. */ + qemu_devtree_setprop_string(fdt, "/", "model", model); + qemu_devtree_setprop(fdt, "/", "compatible", compatible, + sizeof(compatible)); + qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 1); + qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 1); + qemu_devtree_add_subnode(fdt, "/memory"); qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory"); qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb index 8194aa2e6f292fb34023feb596aa19448b8af0d0..25d92f681dec184530af63e2d2cea61cb4cccd04 100644 GIT binary patch literal 1810 zcmb7EyKdA#6rCkONyI||2}FgEk^-Svaira7i!HW+bSd}&;&>;!qn)*l$3_V>REUy} ze?a^K5)yPYv~)`kJs<>}GvjgWMJaNn>$&fHJacD0U-|Q0h?VO?h`taPe`CE1z6M?g zgE}{1|LEk_w^M1INUO+5Lv;y!o5Hq9<9@H(9m>$rwvoAt^sw6tLk672uAUvc+l;-6 zob~N2R<>pzWo;R80ZV7GopV_{%aCs{226a^Hy88}`7l}kC9DIZW|@}3VQGKM+AqVt z$DlbsZg*I36}&&kr!x8;53PyV+JEl-2bG`t3OICe*6QmH60@`0>)Ai`wtXS)Bgk&Q zuQjz<4nOfc1K$I4Z+y%P$V_tkRbi@j*vA}HG1SkA=|PoR_d7SHOvS@4rv;Tj#6Wrt z_V{>?B(J}P?Elf8gFRiIu#4f$4B|S?%jf%5F)iOhzj_b-U0^QHgZJeYm^HlZ7i7|3Fl`}tj{&6j z6;r+gCU{R@z2J<@C64LR&*2-aUgzvG!t0xmeSgMt*6AbLnVE~{5ZA$OM&e0oWJ1-( z;N9&kpZ%8B?=E|g*W7y(3b*bE%t|OWqR}Xq#ssm{+K3IKp2|ud$tNn7kBXB_ia4ER zQK1gC6nT`4@%ra-Ebv?gN4b1l$|OD!tPrSVB#%X`(|Fo&sics3US_x$wHRbkE|a2R zh|{FVQ>|q#HcrDFFs+jEcq^Mk$p{#D-6oL~syZIi`mVGCEr6r;2( I0HBzNe~HoS>i_@% literal 1904 zcmb7FyKWOf6de=fknm8DC@2t$lm;QM;z)Lsg2EP$E)o(c=+I_&Vy`mZ-R!K9Lq$3Y z3VwhepyUgXsOaDeFdsle1r2b{JT|+IQshdwkX=v78Gbc7$l}VZ8_3 z1l9mh>kjn58EQGr64q7nyH6kP^n1NW&#Zy^TR{6%Z@AgadeD9uU@hkI^172-p-Mt6 zHAG{(i?y?3QngJKuM^?t23<4>t2CF*$dT)}#@au(TG- zSyR>PdA<9+3=z)|%2$E5PA0jM!T!{2%jmB`zYB;tf9$E#{|c}-$B$F`oX?Gly)}34 z?FY_Ic^Md5Kcn?|+o|5#?)S}3y$*N(7*6I|eXb)DW&3A8C%}DxXXAa|f@hFDFV~Yh zVeiA9{2gDgrzbA7s(0a@@+2DcI4#HoVo#*^fbWm@Nb>SW@P3cx9?Yb2TCERfrX7uo zyp!cJ4N$?DO#BMiVN+e@{S2Ew2WI=?WOH^SmF=1D;q;CN8n;K`wyy~q!H=M#+t!{ugs4CxKO{VX6A%4^DiFeHU zbKsW{Z?IIv{a5p{U^6|!&RF;~;+)Rh#G;L7>GNWJ2eBfrckvCIujk?$Heb*AG;9m? zs&nz*0%Lg}C%|ohIh>B|82X1_>bk%#9Y~)X$gcyHH~1fbA**C8`#4(qGx&hj%bZ<$ zczGSXuTOu@5p9H-nYnlkb`7vI5{)x0Q;Nn1?`~`L{I|4vcUgm2nPjn4BFZLtSSI^Q zij6Ri3#oMwNu{*d(8(+5c>6YWg2lC+dXG0pLLRBVukg-pwuBFfUT$dr; - #size-cells = <1>; - aliases { serial0 = &serial0; serial1 = &serial1; From f5231aafbfcbf4c43c7612785daa8f26e54ab5bb Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 14:49:20 +0200 Subject: [PATCH 44/72] PPC: e500: dt: create /chosen node dynamically Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 28c7c8c93d..a078e24103 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -101,6 +101,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, sizeof(mem_reg_property)); + qemu_devtree_add_subnode(fdt, "/chosen"); if (initrd_size) { ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_base); From 5da96624391b27f9ead1e0639dbca416926cd660 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 14:51:07 +0200 Subject: [PATCH 45/72] PPC: e500: dt: create /soc8544 node dynamically Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 17 +++++++++++++++++ pc-bios/mpc8544ds.dts | 9 --------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index a078e24103..c7c16c1267 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -43,6 +43,8 @@ #define RAM_SIZES_ALIGN (64UL << 20) #define MPC8544_CCSRBAR_BASE 0xE0000000 +#define MPC8544_CCSRBAR_REGSIZE 0x00001000 +#define MPC8544_CCSRBAR_SIZE 0x00100000 #define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000) #define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500) #define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600) @@ -78,6 +80,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, int i; char compatible[] = "MPC8544DS\0MPC85xxDS"; char model[] = "MPC8544DS"; + char soc[128]; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { @@ -179,6 +182,20 @@ static int mpc8544_load_device_tree(CPUPPCState *env, } } + /* XXX These should go into their respective devices' code */ + snprintf(soc, sizeof(soc), "/soc8544@%x", MPC8544_CCSRBAR_BASE); + qemu_devtree_add_subnode(fdt, soc); + qemu_devtree_setprop_string(fdt, soc, "device_type", "soc"); + qemu_devtree_setprop_string(fdt, soc, "compatible", "simple-bus"); + qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1); + qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1); + qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, MPC8544_CCSRBAR_BASE, + MPC8544_CCSRBAR_SIZE); + qemu_devtree_setprop_cells(fdt, soc, "reg", MPC8544_CCSRBAR_BASE, + MPC8544_CCSRBAR_REGSIZE); + /* XXX should contain a reasonable value */ + qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0); + ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); if (ret < 0) { goto out; diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts index 1eac8ef053..01b53baa68 100644 --- a/pc-bios/mpc8544ds.dts +++ b/pc-bios/mpc8544ds.dts @@ -18,15 +18,6 @@ }; soc8544@e0000000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "simple-bus"; - - ranges = <0x0 0xe0000000 0x100000>; - reg = <0xe0000000 0x1000>; // CCSRBAR 1M - bus-frequency = <0>; // Filled out by uboot. - serial0: serial@4500 { cell-index = <0>; device_type = "serial"; From 0cfc6e8d9e18856b1db0cb5cd5624df7fb19b469 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 14:51:34 +0200 Subject: [PATCH 46/72] PPC: e500: dt: create serial nodes dynamically Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 35 +++++++++++++++++++++++++++++++++++ pc-bios/mpc8544ds.dts | 26 -------------------------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index c7c16c1267..c68e9949b8 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -81,6 +81,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env, char compatible[] = "MPC8544DS\0MPC85xxDS"; char model[] = "MPC8544DS"; char soc[128]; + char ser0[128]; + char ser1[128]; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { @@ -182,6 +184,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, } } + qemu_devtree_add_subnode(fdt, "/aliases"); /* XXX These should go into their respective devices' code */ snprintf(soc, sizeof(soc), "/soc8544@%x", MPC8544_CCSRBAR_BASE); qemu_devtree_add_subnode(fdt, soc); @@ -196,6 +199,38 @@ static int mpc8544_load_device_tree(CPUPPCState *env, /* XXX should contain a reasonable value */ qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0); + /* + * We have to generate ser1 first, because Linux takes the first + * device it finds in the dt as serial output device. And we generate + * devices in reverse order to the dt. + */ + snprintf(ser1, sizeof(ser1), "%s/serial@%x", soc, + MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE); + qemu_devtree_add_subnode(fdt, ser1); + qemu_devtree_setprop_string(fdt, ser1, "device_type", "serial"); + qemu_devtree_setprop_string(fdt, ser1, "compatible", "ns16550"); + qemu_devtree_setprop_cells(fdt, ser1, "reg", MPC8544_SERIAL1_REGS_BASE - + MPC8544_CCSRBAR_BASE, 0x100); + qemu_devtree_setprop_cell(fdt, ser1, "cell-index", 1); + qemu_devtree_setprop_cell(fdt, ser1, "clock-frequency", 0); + qemu_devtree_setprop_cells(fdt, ser1, "interrupts", 42, 2); + qemu_devtree_setprop_phandle(fdt, ser1, "interrupt-parent", mpic); + qemu_devtree_setprop_string(fdt, "/aliases", "serial1", ser1); + + snprintf(ser0, sizeof(ser0), "%s/serial@%x", soc, + MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE); + qemu_devtree_add_subnode(fdt, ser0); + qemu_devtree_setprop_string(fdt, ser0, "device_type", "serial"); + qemu_devtree_setprop_string(fdt, ser0, "compatible", "ns16550"); + qemu_devtree_setprop_cells(fdt, ser0, "reg", MPC8544_SERIAL0_REGS_BASE - + MPC8544_CCSRBAR_BASE, 0x100); + qemu_devtree_setprop_cell(fdt, ser0, "cell-index", 0); + qemu_devtree_setprop_cell(fdt, ser0, "clock-frequency", 0); + qemu_devtree_setprop_cells(fdt, ser0, "interrupts", 42, 2); + qemu_devtree_setprop_phandle(fdt, ser0, "interrupt-parent", mpic); + qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0); + qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0); + ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); if (ret < 0) { goto out; diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts index 01b53baa68..e536ab1e3f 100644 --- a/pc-bios/mpc8544ds.dts +++ b/pc-bios/mpc8544ds.dts @@ -12,32 +12,10 @@ /dts-v1/; / { aliases { - serial0 = &serial0; - serial1 = &serial1; pci0 = &pci0; }; soc8544@e0000000 { - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - mpic: pic@40000 { interrupt-controller; #address-cells = <0>; @@ -85,8 +63,4 @@ #address-cells = <3>; reg = <0xe0008000 0x1000>; }; - - chosen { - linux,stdout-path = "/soc8544@e0000000/serial@4500"; - }; }; From 19ac9deacbadf77532723950ce3e128e18c31573 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 14:51:51 +0200 Subject: [PATCH 47/72] PPC: e500: dt: create mpic node dynamically Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index c68e9949b8..5c2b6ab79a 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -83,6 +83,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env, char soc[128]; char ser0[128]; char ser1[128]; + char mpic[128]; + uint32_t mpic_ph; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { @@ -199,6 +201,20 @@ static int mpc8544_load_device_tree(CPUPPCState *env, /* XXX should contain a reasonable value */ qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0); + snprintf(mpic, sizeof(mpic), "%s/pic@%x", soc, + MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE); + qemu_devtree_add_subnode(fdt, mpic); + qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic"); + qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic"); + qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE - + MPC8544_CCSRBAR_BASE, 0x40000); + qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0); + qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2); + mpic_ph = qemu_devtree_alloc_phandle(fdt); + qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph); + qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); + qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0); + /* * We have to generate ser1 first, because Linux takes the first * device it finds in the dt as serial output device. And we generate From f5038483e4e752b7b4f7053e90873b127bfe4064 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 14:52:46 +0200 Subject: [PATCH 48/72] PPC: e500: dt: create global-utils node dynamically Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 9 +++++++++ pc-bios/mpc8544ds.dts | 6 ------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 5c2b6ab79a..03938b2e3b 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -85,6 +85,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, char ser1[128]; char mpic[128]; uint32_t mpic_ph; + char gutil[128]; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { @@ -247,6 +248,14 @@ static int mpc8544_load_device_tree(CPUPPCState *env, qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0); qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0); + snprintf(gutil, sizeof(gutil), "%s/global-utilities@%x", soc, + MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE); + qemu_devtree_add_subnode(fdt, gutil); + qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); + qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_BASE - + MPC8544_CCSRBAR_BASE, 0x1000); + qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); + ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); if (ret < 0) { goto out; diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts index e536ab1e3f..4c7bd7570b 100644 --- a/pc-bios/mpc8544ds.dts +++ b/pc-bios/mpc8544ds.dts @@ -24,12 +24,6 @@ compatible = "chrp,open-pic"; device_type = "open-pic"; }; - - global-utilities@e0000 { //global utilities block - compatible = "fsl,mpc8544-guts"; - reg = <0xe0000 0x1000>; - fsl,has-rstcr; - }; }; pci0: pci@e0008000 { From 0dbc07985b15940ff3f19529c1f6fd734d535971 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 15:34:34 +0200 Subject: [PATCH 49/72] PPC: e500: dt: create pci node dynamically Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 50 +++++++++++++++++++++++++++++++++++++++++ pc-bios/mpc8544ds.dtb | Bin 1810 -> 72 bytes pc-bios/mpc8544ds.dts | 46 ------------------------------------- 3 files changed, 50 insertions(+), 46 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 03938b2e3b..15df51571c 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -62,6 +62,27 @@ struct boot_info uint32_t entry; }; +static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic) +{ + int i; + const uint32_t tmp[] = { + /* IDSEL 0x11 J17 Slot 1 */ + 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, + 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, + 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, + 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, + + /* IDSEL 0x12 J16 Slot 2 */ + 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, + 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1, + 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, + 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, + }; + for (i = 0; i < (7 * 8); i++) { + pci_map[i] = cpu_to_be32(tmp[i]); + } +} + static int mpc8544_load_device_tree(CPUPPCState *env, target_phys_addr_t addr, uint32_t ramsize, @@ -86,6 +107,11 @@ static int mpc8544_load_device_tree(CPUPPCState *env, char mpic[128]; uint32_t mpic_ph; char gutil[128]; + char pci[128]; + uint32_t pci_map[7 * 8]; + uint32_t pci_ranges[12] = { 0x2000000, 0x0, 0xc0000000, 0xc0000000, 0x0, + 0x20000000, 0x1000000, 0x0, 0x0, 0xe1000000, + 0x0, 0x10000 }; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { @@ -256,6 +282,30 @@ static int mpc8544_load_device_tree(CPUPPCState *env, MPC8544_CCSRBAR_BASE, 0x1000); qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); + snprintf(pci, sizeof(pci), "/pci@%x", MPC8544_PCI_REGS_BASE); + qemu_devtree_add_subnode(fdt, pci); + qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0); + qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); + qemu_devtree_setprop_string(fdt, pci, "device_type", "pci"); + qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, + 0x0, 0x7); + pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic)); + qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map)); + qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic); + qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2); + qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255); + for (i = 0; i < 12; i++) { + pci_ranges[i] = cpu_to_be32(pci_ranges[i]); + } + qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); + qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE, + 0x1000); + qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666); + qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1); + qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2); + qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3); + qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci); + ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); if (ret < 0) { goto out; diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb index 25d92f681dec184530af63e2d2cea61cb4cccd04..90ef5c00243b04f4aa3f812b89d5b37c63be09f2 100644 GIT binary patch literal 72 mcmcb>`|m9S1A_+;TR>?IAT0>Q0zeD{$ZVJxBb31eq&Wct_yhI; literal 1810 zcmb7EyKdA#6rCkONyI||2}FgEk^-Svaira7i!HW+bSd}&;&>;!qn)*l$3_V>REUy} ze?a^K5)yPYv~)`kJs<>}GvjgWMJaNn>$&fHJacD0U-|Q0h?VO?h`taPe`CE1z6M?g zgE}{1|LEk_w^M1INUO+5Lv;y!o5Hq9<9@H(9m>$rwvoAt^sw6tLk672uAUvc+l;-6 zob~N2R<>pzWo;R80ZV7GopV_{%aCs{226a^Hy88}`7l}kC9DIZW|@}3VQGKM+AqVt z$DlbsZg*I36}&&kr!x8;53PyV+JEl-2bG`t3OICe*6QmH60@`0>)Ai`wtXS)Bgk&Q zuQjz<4nOfc1K$I4Z+y%P$V_tkRbi@j*vA}HG1SkA=|PoR_d7SHOvS@4rv;Tj#6Wrt z_V{>?B(J}P?Elf8gFRiIu#4f$4B|S?%jf%5F)iOhzj_b-U0^QHgZJeYm^HlZ7i7|3Fl`}tj{&6j z6;r+gCU{R@z2J<@C64LR&*2-aUgzvG!t0xmeSgMt*6AbLnVE~{5ZA$OM&e0oWJ1-( z;N9&kpZ%8B?=E|g*W7y(3b*bE%t|OWqR}Xq#ssm{+K3IKp2|ud$tNn7kBXB_ia4ER zQK1gC6nT`4@%ra-Ebv?gN4b1l$|OD!tPrSVB#%X`(|Fo&sics3US_x$wHRbkE|a2R zh|{FVQ>|q#HcrDFFs+jEcq^Mk$p{#D-6oL~syZIi`mVGCEr6r;2( I0HBzNe~HoS>i_@% diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts index 4c7bd7570b..16aba2bc5a 100644 --- a/pc-bios/mpc8544ds.dts +++ b/pc-bios/mpc8544ds.dts @@ -11,50 +11,4 @@ /dts-v1/; / { - aliases { - pci0 = &pci0; - }; - - soc8544@e0000000 { - mpic: pic@40000 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; - }; - }; - - pci0: pci@e0008000 { - cell-index = <0>; - compatible = "fsl,mpc8540-pci"; - device_type = "pci"; - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x11 J17 Slot 1 */ - 0x8800 0x0 0x0 0x1 &mpic 0x2 0x1 - 0x8800 0x0 0x0 0x2 &mpic 0x3 0x1 - 0x8800 0x0 0x0 0x3 &mpic 0x4 0x1 - 0x8800 0x0 0x0 0x4 &mpic 0x1 0x1 - - /* IDSEL 0x12 J16 Slot 2 */ - - 0x9000 0x0 0x0 0x1 &mpic 0x3 0x1 - 0x9000 0x0 0x0 0x2 &mpic 0x4 0x1 - 0x9000 0x0 0x0 0x3 &mpic 0x2 0x1 - 0x9000 0x0 0x0 0x4 &mpic 0x1 0x1>; - - interrupt-parent = <&mpic>; - interrupts = <24 2>; - bus-range = <0 255>; - ranges = <0x2000000 0x0 0xc0000000 0xc0000000 0x0 0x20000000 - 0x1000000 0x0 0x0 0xe1000000 0x0 0x10000>; - clock-frequency = <66666666>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0xe0008000 0x1000>; - }; }; From 2636fcb6532eafbb3f1fafba69a107664218e3c8 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 May 2012 15:50:14 +0200 Subject: [PATCH 50/72] PPC: e500: dt: start with empty device tree Now that all of the device tree bits are generated during runtime, we can get rid of the device tree blob and instead start from scratch with an empty device tree. Signed-off-by: Alexander Graf --- Makefile | 1 - hw/ppce500_mpc8544ds.c | 8 +------- pc-bios/mpc8544ds.dtb | Bin 72 -> 0 bytes pc-bios/mpc8544ds.dts | 14 -------------- 4 files changed, 1 insertion(+), 22 deletions(-) delete mode 100644 pc-bios/mpc8544ds.dtb delete mode 100644 pc-bios/mpc8544ds.dts diff --git a/Makefile b/Makefile index a7281b02b6..827e1adac3 100644 --- a/Makefile +++ b/Makefile @@ -260,7 +260,6 @@ pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \ pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \ qemu-icon.bmp \ bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \ -mpc8544ds.dtb \ multiboot.bin linuxboot.bin kvmvapic.bin \ s390-zipl.rom \ spapr-rtas.bin slof.bin \ diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 15df51571c..880ed55fdb 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -92,7 +92,6 @@ static int mpc8544_load_device_tree(CPUPPCState *env, { int ret = -1; uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)}; - char *filename; int fdt_size; void *fdt; uint8_t hypercall[16]; @@ -113,12 +112,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, 0x20000000, 0x1000000, 0x0, 0x0, 0xe1000000, 0x0, 0x10000 }; - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); - if (!filename) { - goto out; - } - fdt = load_device_tree(filename, &fdt_size); - g_free(filename); + fdt = create_device_tree(&fdt_size); if (fdt == NULL) { goto out; } diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb deleted file mode 100644 index 90ef5c00243b04f4aa3f812b89d5b37c63be09f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 72 mcmcb>`|m9S1A_+;TR>?IAT0>Q0zeD{$ZVJxBb31eq&Wct_yhI; diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts deleted file mode 100644 index 16aba2bc5a..0000000000 --- a/pc-bios/mpc8544ds.dts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * MPC8544 DS Device Tree Source - * - * Copyright 2007, 2008 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -/dts-v1/; -/ { -}; From 25b42708cd011e7d4b37313f7f83ac2551e5370f Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 May 2012 00:11:33 +0200 Subject: [PATCH 51/72] dt: Add -machine dumpdtb option to dump the current dtb Now that we are dynamically creating the dtb, it's really useful to be able to dump the created blob for debugging. This patch implements a -machine dumpdtb= option for e500 that dumps the dtb exactly in the form the guest would get it to disk. It can then be analyzed by dtc to get information about the guest configuration. Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 18 ++++++++++++++++++ qemu-config.c | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 880ed55fdb..7c6edc22e1 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -111,6 +111,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env, uint32_t pci_ranges[12] = { 0x2000000, 0x0, 0xc0000000, 0xc0000000, 0x0, 0x20000000, 0x1000000, 0x0, 0x0, 0xe1000000, 0x0, 0x10000 }; + QemuOpts *machine_opts; + const char *dumpdtb = NULL; fdt = create_device_tree(&fdt_size); if (fdt == NULL) { @@ -300,6 +302,22 @@ static int mpc8544_load_device_tree(CPUPPCState *env, qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3); qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci); + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + dumpdtb = qemu_opt_get(machine_opts, "dumpdtb"); + } + if (dumpdtb) { + /* Dump the dtb to a file and quit */ + FILE *f = fopen(dumpdtb, "wb"); + size_t len; + len = fwrite(fdt, fdt_size, 1, f); + fclose(f); + if (len != fdt_size) { + exit(1); + } + exit(0); + } + ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); if (ret < 0) { goto out; diff --git a/qemu-config.c b/qemu-config.c index bb3bff426a..5bbebafa1b 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -583,6 +583,10 @@ static QemuOptsList qemu_machine_opts = { .name = "dtb", .type = QEMU_OPT_STRING, .help = "Linux kernel device tree file", + }, { + .name = "dumpdtb", + .type = QEMU_OPT_STRING, + .help = "Dump current dtb to a file and quit", }, { /* End of list */ } }, From 1d2e5c5235dc722bc9e12218d5f00c12f8bdc5bb Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 May 2012 01:56:46 +0200 Subject: [PATCH 52/72] PPC: e500: dt: use 64bit cell helper We have a nice 64bit helper to ease the device tree generation and make the code more readable when creating 64bit 2-cell parameters. Use it when generating the device tree. Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 7c6edc22e1..5fa2089fb8 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -174,7 +174,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, the first node as boot node and be happy */ for (i = smp_cpus - 1; i >= 0; i--) { char cpu_name[128]; - uint64_t cpu_release_addr = cpu_to_be64(MPC8544_SPIN_BASE + (i * 0x20)); + uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20); for (env = first_cpu; env != NULL; env = env->next_cpu) { if (env->cpu_index == i) { @@ -202,8 +202,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env, if (env->cpu_index) { qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled"); qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table"); - qemu_devtree_setprop(fdt, cpu_name, "cpu-release-addr", - &cpu_release_addr, sizeof(cpu_release_addr)); + qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr", + cpu_release_addr); } else { qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay"); } From 7f47b41f3f36fd0618758580121ddeb0407069b7 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 May 2012 02:14:46 +0200 Subject: [PATCH 53/72] PPC: e500: dt: use target_phys_addr_t for ramsize We're passing the ram size as uint32_t, capping it to 32 bits atm. Change to target_phys_addr_t (uint64_t) to make sure we have all the bits. Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 5fa2089fb8..f8a3d9abcf 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -85,7 +85,7 @@ static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic) static int mpc8544_load_device_tree(CPUPPCState *env, target_phys_addr_t addr, - uint32_t ramsize, + target_phys_addr_t ramsize, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, const char *kernel_cmdline) From d1b935659b77ff8e9d4cb84e3f75679f634401f3 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 22 May 2012 14:28:50 +0200 Subject: [PATCH 54/72] PPC: e500: enable manual loading of dtb blob We want to be able to override the automatically created device tree by using the -dtb option. Implement this for the mpc8544ds machine. Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index f8a3d9abcf..fa10df226f 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -113,6 +113,27 @@ static int mpc8544_load_device_tree(CPUPPCState *env, 0x0, 0x10000 }; QemuOpts *machine_opts; const char *dumpdtb = NULL; + const char *dtb_file = NULL; + + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + dumpdtb = qemu_opt_get(machine_opts, "dumpdtb"); + dtb_file = qemu_opt_get(machine_opts, "dtb"); + } + + if (dtb_file) { + char *filename; + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file); + if (!filename) { + goto out; + } + + fdt = load_device_tree(filename, &fdt_size); + if (!fdt) { + goto out; + } + goto done; + } fdt = create_device_tree(&fdt_size); if (fdt == NULL) { @@ -302,10 +323,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3); qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci); - machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (machine_opts) { - dumpdtb = qemu_opt_get(machine_opts, "dumpdtb"); - } +done: if (dumpdtb) { /* Dump the dtb to a file and quit */ FILE *f = fopen(dumpdtb, "wb"); From 1337ae1e5b20802d3167563d6c733172da513ca7 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 May 2012 01:45:01 +0200 Subject: [PATCH 55/72] Revert "dt: temporarily disable subtree creation failure check" This reverts commit "dt: temporarily disable subtree creation failure check" which was meant as a temporary solution to keep external and dynamic device tree construction intact. Now that we switched to fully dynamic dt construction, it's no longer necessary. Signed-off-by: Alexander Graf --- device_tree.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/device_tree.c b/device_tree.c index c8d68c203e..cc83f0fb01 100644 --- a/device_tree.c +++ b/device_tree.c @@ -239,13 +239,11 @@ int qemu_devtree_add_subnode(void *fdt, const char *name) } retval = fdt_add_subnode(fdt, parent, basename); -#if 0 if (retval < 0) { fprintf(stderr, "FDT: Failed to create subnode %s: %s\n", name, fdt_strerror(retval)); exit(1); } -#endif g_free(dupname); return retval; From 518c7fb44f2182cde943dc64f88cb2fd4e4ff6b5 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 6 Jun 2012 00:14:34 +0200 Subject: [PATCH 56/72] PPC: e500: Use new MPIC dt format Due to popular demand, we're updating the way we generate the MPIC node and interrupt lines based on what the current state of art is. Requested-by: Scott Wood Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index fa10df226f..e3e0659594 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -67,18 +67,18 @@ static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic) int i; const uint32_t tmp[] = { /* IDSEL 0x11 J17 Slot 1 */ - 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, - 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, - 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, - 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, + 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, 0x0, 0x0, + 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, 0x0, 0x0, + 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, 0x0, 0x0, + 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0, /* IDSEL 0x12 J16 Slot 2 */ - 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, - 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1, - 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, - 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, + 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, 0x0, 0x0, + 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1, 0x0, 0x0, + 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, 0x0, 0x0, + 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0, }; - for (i = 0; i < (7 * 8); i++) { + for (i = 0; i < ARRAY_SIZE(tmp); i++) { pci_map[i] = cpu_to_be32(tmp[i]); } } @@ -107,7 +107,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, uint32_t mpic_ph; char gutil[128]; char pci[128]; - uint32_t pci_map[7 * 8]; + uint32_t pci_map[9 * 8]; uint32_t pci_ranges[12] = { 0x2000000, 0x0, 0xc0000000, 0xc0000000, 0x0, 0x20000000, 0x1000000, 0x0, 0x0, 0xe1000000, 0x0, 0x10000 }; @@ -249,15 +249,18 @@ static int mpc8544_load_device_tree(CPUPPCState *env, MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE); qemu_devtree_add_subnode(fdt, mpic); qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic"); - qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic"); + qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE, 0x40000); qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0); - qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2); + qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 4); mpic_ph = qemu_devtree_alloc_phandle(fdt); qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph); qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0); + qemu_devtree_setprop(fdt, mpic, "big-endian", NULL, 0); + qemu_devtree_setprop(fdt, mpic, "single-cpu-affinity", NULL, 0); + qemu_devtree_setprop_cell(fdt, mpic, "last-interrupt-source", 255); /* * We have to generate ser1 first, because Linux takes the first @@ -273,7 +276,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, MPC8544_CCSRBAR_BASE, 0x100); qemu_devtree_setprop_cell(fdt, ser1, "cell-index", 1); qemu_devtree_setprop_cell(fdt, ser1, "clock-frequency", 0); - qemu_devtree_setprop_cells(fdt, ser1, "interrupts", 42, 2); + qemu_devtree_setprop_cells(fdt, ser1, "interrupts", 42, 2, 0, 0); qemu_devtree_setprop_phandle(fdt, ser1, "interrupt-parent", mpic); qemu_devtree_setprop_string(fdt, "/aliases", "serial1", ser1); @@ -286,7 +289,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, MPC8544_CCSRBAR_BASE, 0x100); qemu_devtree_setprop_cell(fdt, ser0, "cell-index", 0); qemu_devtree_setprop_cell(fdt, ser0, "clock-frequency", 0); - qemu_devtree_setprop_cells(fdt, ser0, "interrupts", 42, 2); + qemu_devtree_setprop_cells(fdt, ser0, "interrupts", 42, 2, 0, 0); qemu_devtree_setprop_phandle(fdt, ser0, "interrupt-parent", mpic); qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0); qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0); @@ -309,7 +312,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic)); qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map)); qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic); - qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2); + qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2, 0, 0); qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255); for (i = 0; i < 12; i++) { pci_ranges[i] = cpu_to_be32(pci_ranges[i]); From ebb9518aab7a6c8bb78636494fa60b2742d00251 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 6 Jun 2012 00:20:20 +0200 Subject: [PATCH 57/72] PPC: e500: Use new SOC dt format Due to popular demand, let's clean up the soc node a bit and use more recent dt notions. Requested-by: Scott Wood Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index e3e0659594..7dc3a07aec 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -43,7 +43,6 @@ #define RAM_SIZES_ALIGN (64UL << 20) #define MPC8544_CCSRBAR_BASE 0xE0000000 -#define MPC8544_CCSRBAR_REGSIZE 0x00001000 #define MPC8544_CCSRBAR_SIZE 0x00100000 #define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000) #define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500) @@ -99,6 +98,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, uint32_t tb_freq = 400000000; int i; char compatible[] = "MPC8544DS\0MPC85xxDS"; + char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; char model[] = "MPC8544DS"; char soc[128]; char ser0[128]; @@ -232,16 +232,15 @@ static int mpc8544_load_device_tree(CPUPPCState *env, qemu_devtree_add_subnode(fdt, "/aliases"); /* XXX These should go into their respective devices' code */ - snprintf(soc, sizeof(soc), "/soc8544@%x", MPC8544_CCSRBAR_BASE); + snprintf(soc, sizeof(soc), "/soc@%x", MPC8544_CCSRBAR_BASE); qemu_devtree_add_subnode(fdt, soc); qemu_devtree_setprop_string(fdt, soc, "device_type", "soc"); - qemu_devtree_setprop_string(fdt, soc, "compatible", "simple-bus"); + qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb, + sizeof(compatible_sb)); qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1); qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1); qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, MPC8544_CCSRBAR_BASE, MPC8544_CCSRBAR_SIZE); - qemu_devtree_setprop_cells(fdt, soc, "reg", MPC8544_CCSRBAR_BASE, - MPC8544_CCSRBAR_REGSIZE); /* XXX should contain a reasonable value */ qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0); From ed2bc496eff0d78544d46c637cf11a29114666c5 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 6 Jun 2012 00:30:36 +0200 Subject: [PATCH 58/72] PPC: e500: Define addresses as always 64bit Every time we use an address constant, it needs to potentially fit into a 64bit physical address space. So let's define things accordingly. Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 7dc3a07aec..c6a09bba3f 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -42,17 +42,17 @@ #define RAM_SIZES_ALIGN (64UL << 20) -#define MPC8544_CCSRBAR_BASE 0xE0000000 -#define MPC8544_CCSRBAR_SIZE 0x00100000 -#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000) -#define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500) -#define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600) -#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000) -#define MPC8544_PCI_REGS_SIZE 0x1000 -#define MPC8544_PCI_IO 0xE1000000 -#define MPC8544_PCI_IOLEN 0x10000 -#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000) -#define MPC8544_SPIN_BASE 0xEF000000 +#define MPC8544_CCSRBAR_BASE 0xE0000000ULL +#define MPC8544_CCSRBAR_SIZE 0x00100000ULL +#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000ULL) +#define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500ULL) +#define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600ULL) +#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000ULL) +#define MPC8544_PCI_REGS_SIZE 0x1000ULL +#define MPC8544_PCI_IO 0xE1000000ULL +#define MPC8544_PCI_IOLEN 0x10000ULL +#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000ULL) +#define MPC8544_SPIN_BASE 0xEF000000ULL struct boot_info { @@ -232,7 +232,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, qemu_devtree_add_subnode(fdt, "/aliases"); /* XXX These should go into their respective devices' code */ - snprintf(soc, sizeof(soc), "/soc@%x", MPC8544_CCSRBAR_BASE); + snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE); qemu_devtree_add_subnode(fdt, soc); qemu_devtree_setprop_string(fdt, soc, "device_type", "soc"); qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb, @@ -244,7 +244,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, /* XXX should contain a reasonable value */ qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0); - snprintf(mpic, sizeof(mpic), "%s/pic@%x", soc, + snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE); qemu_devtree_add_subnode(fdt, mpic); qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic"); @@ -266,7 +266,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, * device it finds in the dt as serial output device. And we generate * devices in reverse order to the dt. */ - snprintf(ser1, sizeof(ser1), "%s/serial@%x", soc, + snprintf(ser1, sizeof(ser1), "%s/serial@%llx", soc, MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE); qemu_devtree_add_subnode(fdt, ser1); qemu_devtree_setprop_string(fdt, ser1, "device_type", "serial"); @@ -279,7 +279,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, qemu_devtree_setprop_phandle(fdt, ser1, "interrupt-parent", mpic); qemu_devtree_setprop_string(fdt, "/aliases", "serial1", ser1); - snprintf(ser0, sizeof(ser0), "%s/serial@%x", soc, + snprintf(ser0, sizeof(ser0), "%s/serial@%llx", soc, MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE); qemu_devtree_add_subnode(fdt, ser0); qemu_devtree_setprop_string(fdt, ser0, "device_type", "serial"); @@ -293,7 +293,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0); qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0); - snprintf(gutil, sizeof(gutil), "%s/global-utilities@%x", soc, + snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc, MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE); qemu_devtree_add_subnode(fdt, gutil); qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); @@ -301,7 +301,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, MPC8544_CCSRBAR_BASE, 0x1000); qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); - snprintf(pci, sizeof(pci), "/pci@%x", MPC8544_PCI_REGS_BASE); + snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE); qemu_devtree_add_subnode(fdt, pci); qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0); qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); From 3627757e32e2c9fcee84e218746639aa2bfb1723 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 6 Jun 2012 00:25:06 +0200 Subject: [PATCH 59/72] PPC: e500: Extend address/size of / to 64bit We want to be able to support >= 4GB of RAM. To do so, we need to be able to tell the guest OS how much RAM it has. However, that information today is capped to 32bit. So let's extend the offset and size fields to 64bit, so we can fit in big addresses and even one day - if we wish to do so - map devices above 32bit. Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index c6a09bba3f..bf48bc7d75 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -90,7 +90,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, const char *kernel_cmdline) { int ret = -1; - uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)}; + uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) }; int fdt_size; void *fdt; uint8_t hypercall[16]; @@ -108,9 +108,16 @@ static int mpc8544_load_device_tree(CPUPPCState *env, char gutil[128]; char pci[128]; uint32_t pci_map[9 * 8]; - uint32_t pci_ranges[12] = { 0x2000000, 0x0, 0xc0000000, 0xc0000000, 0x0, - 0x20000000, 0x1000000, 0x0, 0x0, 0xe1000000, - 0x0, 0x10000 }; + uint32_t pci_ranges[14] = + { + 0x2000000, 0x0, 0xc0000000, + 0x0, 0xc0000000, + 0x0, 0x20000000, + + 0x1000000, 0x0, 0x0, + 0x0, 0xe1000000, + 0x0, 0x10000, + }; QemuOpts *machine_opts; const char *dumpdtb = NULL; const char *dtb_file = NULL; @@ -144,8 +151,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env, qemu_devtree_setprop_string(fdt, "/", "model", model); qemu_devtree_setprop(fdt, "/", "compatible", compatible, sizeof(compatible)); - qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 1); - qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 1); + qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2); + qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2); qemu_devtree_add_subnode(fdt, "/memory"); qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory"); @@ -239,7 +246,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env, sizeof(compatible_sb)); qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1); qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1); - qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, MPC8544_CCSRBAR_BASE, + qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, + MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE, MPC8544_CCSRBAR_SIZE); /* XXX should contain a reasonable value */ qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0); @@ -313,12 +321,12 @@ static int mpc8544_load_device_tree(CPUPPCState *env, qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic); qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2, 0, 0); qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255); - for (i = 0; i < 12; i++) { + for (i = 0; i < 14; i++) { pci_ranges[i] = cpu_to_be32(pci_ranges[i]); } qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); - qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE, - 0x1000); + qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32, + MPC8544_PCI_REGS_BASE, 0, 0x1000); qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666); qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1); qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2); From 4b1b1c896fb38d435f3d350c44b1bdc8b56600a4 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 6 Jun 2012 01:01:23 +0200 Subject: [PATCH 60/72] dt: Add global option to set phandle start offset If anyone outside of QEMU wants to mess with a QEMU generated device tree, he needs to know which range phandles are valid in. So let's expose a machine option that an external program can use to set the start allocate id for phandles in QEMU. Signed-off-by: Alexander Graf --- device_tree.c | 28 +++++++++++++++++++++++++++- qemu-config.c | 4 ++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/device_tree.c b/device_tree.c index cc83f0fb01..acae53e6b6 100644 --- a/device_tree.c +++ b/device_tree.c @@ -22,6 +22,8 @@ #include "qemu-common.h" #include "device_tree.h" #include "hw/loader.h" +#include "qemu-option.h" +#include "qemu-config.h" #include @@ -200,7 +202,31 @@ int qemu_devtree_setprop_phandle(void *fdt, const char *node_path, uint32_t qemu_devtree_alloc_phandle(void *fdt) { - static int phandle = 0x8000; + static int phandle = 0x0; + + /* + * We need to find out if the user gave us special instruction at + * which phandle id to start allocting phandles. + */ + if (!phandle) { + QemuOpts *machine_opts; + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + const char *phandle_start; + phandle_start = qemu_opt_get(machine_opts, "phandle_start"); + if (phandle_start) { + phandle = strtoul(phandle_start, NULL, 0); + } + } + } + + if (!phandle) { + /* + * None or invalid phandle given on the command line, so fall back to + * default starting point. + */ + phandle = 0x8000; + } return phandle++; } diff --git a/qemu-config.c b/qemu-config.c index 5bbebafa1b..2cd27262e9 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -587,6 +587,10 @@ static QemuOptsList qemu_machine_opts = { .name = "dumpdtb", .type = QEMU_OPT_STRING, .help = "Dump current dtb to a file and quit", + }, { + .name = "phandle_start", + .type = QEMU_OPT_STRING, + .help = "The first phandle ID we may generate dynamically", }, { /* End of list */ } }, From a053a7cea61da679fe87ce491701f3874ae42371 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 6 Jun 2012 01:19:40 +0200 Subject: [PATCH 61/72] PPC: e500: Refactor serial dt generation When generating serial port device tree nodes, we duplicate quite a bit of code, because there are 2 of them in the mpc8544ds board we emulate. Shove the generating code into a function, so we duplicate less code. Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 54 ++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index bf48bc7d75..f6da25bb65 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -82,6 +82,28 @@ static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic) } } +static void dt_serial_create(void *fdt, unsigned long long offset, + const char *soc, const char *mpic, + const char *alias, int idx, bool defcon) +{ + char ser[128]; + + snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset); + qemu_devtree_add_subnode(fdt, ser); + qemu_devtree_setprop_string(fdt, ser, "device_type", "serial"); + qemu_devtree_setprop_string(fdt, ser, "compatible", "ns16550"); + qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100); + qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx); + qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0); + qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2, 0, 0); + qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic); + qemu_devtree_setprop_string(fdt, "/aliases", alias, ser); + + if (defcon) { + qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser); + } +} + static int mpc8544_load_device_tree(CPUPPCState *env, target_phys_addr_t addr, target_phys_addr_t ramsize, @@ -101,8 +123,6 @@ static int mpc8544_load_device_tree(CPUPPCState *env, char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; char model[] = "MPC8544DS"; char soc[128]; - char ser0[128]; - char ser1[128]; char mpic[128]; uint32_t mpic_ph; char gutil[128]; @@ -274,32 +294,10 @@ static int mpc8544_load_device_tree(CPUPPCState *env, * device it finds in the dt as serial output device. And we generate * devices in reverse order to the dt. */ - snprintf(ser1, sizeof(ser1), "%s/serial@%llx", soc, - MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE); - qemu_devtree_add_subnode(fdt, ser1); - qemu_devtree_setprop_string(fdt, ser1, "device_type", "serial"); - qemu_devtree_setprop_string(fdt, ser1, "compatible", "ns16550"); - qemu_devtree_setprop_cells(fdt, ser1, "reg", MPC8544_SERIAL1_REGS_BASE - - MPC8544_CCSRBAR_BASE, 0x100); - qemu_devtree_setprop_cell(fdt, ser1, "cell-index", 1); - qemu_devtree_setprop_cell(fdt, ser1, "clock-frequency", 0); - qemu_devtree_setprop_cells(fdt, ser1, "interrupts", 42, 2, 0, 0); - qemu_devtree_setprop_phandle(fdt, ser1, "interrupt-parent", mpic); - qemu_devtree_setprop_string(fdt, "/aliases", "serial1", ser1); - - snprintf(ser0, sizeof(ser0), "%s/serial@%llx", soc, - MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE); - qemu_devtree_add_subnode(fdt, ser0); - qemu_devtree_setprop_string(fdt, ser0, "device_type", "serial"); - qemu_devtree_setprop_string(fdt, ser0, "compatible", "ns16550"); - qemu_devtree_setprop_cells(fdt, ser0, "reg", MPC8544_SERIAL0_REGS_BASE - - MPC8544_CCSRBAR_BASE, 0x100); - qemu_devtree_setprop_cell(fdt, ser0, "cell-index", 0); - qemu_devtree_setprop_cell(fdt, ser0, "clock-frequency", 0); - qemu_devtree_setprop_cells(fdt, ser0, "interrupts", 42, 2, 0, 0); - qemu_devtree_setprop_phandle(fdt, ser0, "interrupt-parent", mpic); - qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0); - qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0); + dt_serial_create(fdt, MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE, + soc, mpic, "serial1", 1, false); + dt_serial_create(fdt, MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE, + soc, mpic, "serial0", 0, true); snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc, MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE); From 45e9dfb2fdd6ab7b60f823a1ee5ed2f2722beaf6 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 20 Jun 2012 20:39:59 +0200 Subject: [PATCH 62/72] dt: make setprop argument static Whatever we pass in to qemu_devtree_setprop to put into the device tree will not get modified by that function, so it can easily be declared const. Signed-off-by: Alexander Graf Reviewed-by: Peter Crosthwaite --- device_tree.c | 2 +- device_tree.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/device_tree.c b/device_tree.c index acae53e6b6..b366fddeaf 100644 --- a/device_tree.c +++ b/device_tree.c @@ -127,7 +127,7 @@ static int findnode_nofail(void *fdt, const char *node_path) } int qemu_devtree_setprop(void *fdt, const char *node_path, - const char *property, void *val_array, int size) + const char *property, const void *val_array, int size) { int r; diff --git a/device_tree.h b/device_tree.h index 4898d957af..2244270b2d 100644 --- a/device_tree.h +++ b/device_tree.h @@ -18,7 +18,7 @@ void *create_device_tree(int *sizep); void *load_device_tree(const char *filename_path, int *sizep); int qemu_devtree_setprop(void *fdt, const char *node_path, - const char *property, void *val_array, int size); + const char *property, const void *val_array, int size); int qemu_devtree_setprop_cell(void *fdt, const char *node_path, const char *property, uint32_t val); int qemu_devtree_setprop_u64(void *fdt, const char *node_path, From caedc737d27dd697641cb75ef6c5c27562c8044a Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 20 Jun 2012 20:46:22 +0200 Subject: [PATCH 63/72] PPC: e500: allow users to set the /compatible property via -machine Device trees usually have a node /compatible, which indicate which machine type we're looking at. For quick prototyping, it can be very useful to change the contents of that node via the command line. Thus, introduce a new option to -machine called dt_compatible, which when set changes the /compatible contents to its value. Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 12 +++++++++--- qemu-config.c | 4 ++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index f6da25bb65..d38ad99249 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -119,7 +119,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env, uint32_t clock_freq = 400000000; uint32_t tb_freq = 400000000; int i; - char compatible[] = "MPC8544DS\0MPC85xxDS"; + const char *compatible = "MPC8544DS\0MPC85xxDS"; + int compatible_len = sizeof("MPC8544DS\0MPC85xxDS"); char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; char model[] = "MPC8544DS"; char soc[128]; @@ -144,8 +145,14 @@ static int mpc8544_load_device_tree(CPUPPCState *env, machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); if (machine_opts) { + const char *tmp; dumpdtb = qemu_opt_get(machine_opts, "dumpdtb"); dtb_file = qemu_opt_get(machine_opts, "dtb"); + tmp = qemu_opt_get(machine_opts, "dt_compatible"); + if (tmp) { + compatible = tmp; + compatible_len = strlen(compatible) + 1; + } } if (dtb_file) { @@ -169,8 +176,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, /* Manipulate device tree in memory. */ qemu_devtree_setprop_string(fdt, "/", "model", model); - qemu_devtree_setprop(fdt, "/", "compatible", compatible, - sizeof(compatible)); + qemu_devtree_setprop(fdt, "/", "compatible", compatible, compatible_len); qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2); qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2); diff --git a/qemu-config.c b/qemu-config.c index 2cd27262e9..5c3296b8c6 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -591,6 +591,10 @@ static QemuOptsList qemu_machine_opts = { .name = "phandle_start", .type = QEMU_OPT_STRING, .help = "The first phandle ID we may generate dynamically", + }, { + .name = "dt_compatible", + .type = QEMU_OPT_STRING, + .help = "Overrides the \"compatible\" property of the dt root node", }, { /* End of list */ } }, From 5025d5421d3c6e705669f365192a7edf17b1aad8 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 20 Jun 2012 20:58:27 +0200 Subject: [PATCH 64/72] uImage: increase the gzip load size Recent u-boot has different defines for its gzip extract buffer, but the common ground seems to be 64MB. So let's bump it up to that, enabling me to load my test image again ;). Signed-off-by: Alexander Graf --- hw/loader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/loader.c b/hw/loader.c index 7d64113e7f..33acc2fdab 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -377,9 +377,9 @@ static void zfree(void *x, void *addr) #define DEFLATED 8 -/* This is the maximum in uboot, so if a uImage overflows this, it would +/* This is the usual maximum in uboot, so if a uImage overflows this, it would * overflow on real hardware too. */ -#define UBOOT_MAX_GUNZIP_BYTES 0x800000 +#define UBOOT_MAX_GUNZIP_BYTES (64 << 20) static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, size_t srclen) From 84755ed51e6266b115322834933ce404a2fbf3f9 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 20 Jun 2012 21:19:09 +0200 Subject: [PATCH 65/72] PPC: Add some booke SPR defines The number of SPRs avaiable in different PowerPC chip is still increasing. Add definitions for the MAS7_MAS3 SPR and all currently known bits in EPCR. Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 67e699cdc9..12200ab443 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1395,6 +1395,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) #define SPR_BOOKE_TLB1PS (0x159) #define SPR_BOOKE_TLB2PS (0x15A) #define SPR_BOOKE_TLB3PS (0x15B) +#define SPR_BOOKE_MAS7_MAS3 (0x174) #define SPR_BOOKE_IVOR0 (0x190) #define SPR_BOOKE_IVOR1 (0x191) #define SPR_BOOKE_IVOR2 (0x192) @@ -1762,6 +1763,27 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) #define SPR_604_HID15 (0x3FF) #define SPR_E500_SVR (0x3FF) +/* Disable MAS Interrupt Updates for Hypervisor */ +#define EPCR_DMIUH (1 << 22) +/* Disable Guest TLB Management Instructions */ +#define EPCR_DGTMI (1 << 23) +/* Guest Interrupt Computation Mode */ +#define EPCR_GICM (1 << 24) +/* Interrupt Computation Mode */ +#define EPCR_ICM (1 << 25) +/* Disable Embedded Hypervisor Debug */ +#define EPCR_DUVD (1 << 26) +/* Instruction Storage Interrupt Directed to Guest State */ +#define EPCR_ISIGS (1 << 27) +/* Data Storage Interrupt Directed to Guest State */ +#define EPCR_DSIGS (1 << 28) +/* Instruction TLB Error Interrupt Directed to Guest State */ +#define EPCR_ITLBGS (1 << 29) +/* Data TLB Error Interrupt Directed to Guest State */ +#define EPCR_DTLBGS (1 << 30) +/* External Input Interrupt Directed to Guest State */ +#define EPCR_EXTGS (1 << 31) + /*****************************************************************************/ /* PowerPC Instructions types definitions */ enum { From e42a61f185f859246c14445b6e98e195eb3b977b Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 20 Jun 2012 21:20:29 +0200 Subject: [PATCH 66/72] PPC: Add support for MSR_CM The BookE variant of MSR_SF is MSR_CM. Implement everything it takes in TCG to support running 64bit code with MSR_CM set. Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 9 +++++++++ target-ppc/excp_helper.c | 9 +++++---- target-ppc/mem_helper.c | 2 +- target-ppc/translate.c | 2 +- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 12200ab443..7a77fff077 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -2212,6 +2212,15 @@ static inline uint32_t booke206_tlbnps(CPUPPCState *env, const int tlbn) #endif +static inline bool msr_is_64bit(CPUPPCState *env, target_ulong msr) +{ + if (env->mmu_model == POWERPC_MMU_BOOKE206) { + return msr & (1ULL << MSR_CM); + } + + return msr & (1ULL << MSR_SF); +} + extern void (*cpu_ppc_hypercall)(CPUPPCState *); static inline bool cpu_has_work(CPUPPCState *env) diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index c7762b99c5..1a593f6f3f 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -608,10 +608,11 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) vector |= env->excp_prefix; #if defined(TARGET_PPC64) if (excp_model == POWERPC_EXCP_BOOKE) { - if (!msr_icm) { - vector = (uint32_t)vector; - } else { + if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) { + /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */ new_msr |= (target_ulong)1 << MSR_CM; + } else { + vector = (uint32_t)vector; } } else { if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) { @@ -803,7 +804,7 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr, target_ulong msrm, int keep_msrh) { #if defined(TARGET_PPC64) - if (msr & (1ULL << MSR_SF)) { + if (msr_is_64bit(env, msr)) { nip = (uint64_t)nip; msr &= (uint64_t)msrm; } else { diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c index ebcd7b24a8..5b5f1bdd23 100644 --- a/target-ppc/mem_helper.c +++ b/target-ppc/mem_helper.c @@ -35,7 +35,7 @@ static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr, target_long arg) { #if defined(TARGET_PPC64) - if (!msr_sf) { + if (!msr_is_64bit(env, env->msr)) { return (uint32_t)(addr + arg); } else #endif diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 9103fd5776..73ee74be21 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -9626,7 +9626,7 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, ctx.access_type = -1; ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0; #if defined(TARGET_PPC64) - ctx.sf_mode = msr_sf; + ctx.sf_mode = msr_is_64bit(env, env->msr); ctx.has_cfar = !!(env->flags & POWERPC_FLAG_CFAR); #endif ctx.fpu_enabled = msr_fp; From 2a7a47fc6c19703a849a34243701a09052cb1bc6 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 20 Jun 2012 21:27:02 +0200 Subject: [PATCH 67/72] PPC: BookE: Implement EPR SPR On the e500 series, accessing SPR_EPR magically turns into an access at that CPU's IACK register on the MPIC. Implement that logic to get kernels that make use of that feature work. Signed-off-by: Alexander Graf --- hw/ppce500_mpc8544ds.c | 1 + target-ppc/Makefile.objs | 1 + target-ppc/cpu.h | 1 + target-ppc/helper.h | 1 + target-ppc/mpic_helper.c | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 39 insertions(+) create mode 100644 target-ppc/mpic_helper.c diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index d38ad99249..8b9fd83ce1 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -469,6 +469,7 @@ static void mpc8544ds_init(ram_addr_t ram_size, irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; env->spr[SPR_BOOKE_PIR] = env->cpu_index = i; + env->mpic_cpu_base = MPC8544_MPIC_REGS_BASE + 0x20000; ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500); diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 6c11ef84b7..237a0ed4f7 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -9,3 +9,4 @@ obj-y += mmu_helper.o obj-y += timebase_helper.o obj-y += misc_helper.o obj-y += mem_helper.o +obj-y += mpic_helper.o diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 7a77fff077..652a35a39f 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1066,6 +1066,7 @@ struct CPUPPCState { target_ulong ivor_mask; target_ulong ivpr_mask; target_ulong hreset_vector; + target_phys_addr_t mpic_cpu_base; #endif /* Those resources are used only during code translation */ diff --git a/target-ppc/helper.h b/target-ppc/helper.h index ddab97b379..fd04c063e2 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -405,6 +405,7 @@ DEF_HELPER_2(store_40x_dbcr0, void, env, tl) DEF_HELPER_2(store_40x_sler, void, env, tl) DEF_HELPER_2(store_booke_tcr, void, env, tl) DEF_HELPER_2(store_booke_tsr, void, env, tl) +DEF_HELPER_1(load_epr, tl, env) DEF_HELPER_3(store_ibatl, void, env, i32, tl) DEF_HELPER_3(store_ibatu, void, env, i32, tl) DEF_HELPER_3(store_dbatl, void, env, i32, tl) diff --git a/target-ppc/mpic_helper.c b/target-ppc/mpic_helper.c new file mode 100644 index 0000000000..2c6a4d30a9 --- /dev/null +++ b/target-ppc/mpic_helper.c @@ -0,0 +1,35 @@ +/* + * PowerPC emulation 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, see . + */ +#include "cpu.h" +#include "helper.h" + +/*****************************************************************************/ +/* SPR accesses */ + +#if !defined(CONFIG_USER_ONLY) +/* + * This is an ugly helper for EPR, which is basically the same as accessing + * the IACK (PIAC) register on the MPIC. Because we model the MPIC as a device + * that can only talk to the CPU through MMIO, let's access it that way! + */ +target_ulong helper_load_epr(CPUPPCState *env) +{ + return ldl_phys(env->mpic_cpu_base + 0xA0); +} +#endif From e9cd84b90b7c6df64044b1e57730b8a9be5de26b Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 21 Jun 2012 15:17:59 +0200 Subject: [PATCH 68/72] PPC: BookE: Make ivpr selectable by CPU type IVPR can either hold 32 or 64 bit addresses, depending on the CPU type. Let the CPU initialization function pass in its mask itself, so we can easily extend it. Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 57027a2883..98695ab239 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2804,7 +2804,7 @@ static void init_excp_G2 (CPUPPCState *env) #endif } -static void init_excp_e200 (CPUPPCState *env) +static void init_excp_e200(CPUPPCState *env, target_ulong ivpr_mask) { #if !defined(CONFIG_USER_ONLY) env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000FFC; @@ -2829,7 +2829,7 @@ static void init_excp_e200 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_EFPRI] = 0x00000000; env->hreset_excp_prefix = 0x00000000UL; env->ivor_mask = 0x0000FFF7UL; - env->ivpr_mask = 0xFFFF0000UL; + env->ivpr_mask = ivpr_mask; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -4307,7 +4307,7 @@ static void init_proc_e200 (CPUPPCState *env) env->id_tlbs = 0; env->tlb_type = TLB_EMB; #endif - init_excp_e200(env); + init_excp_e200(env, 0xFFFF0000UL); env->dcache_line_size = 32; env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ @@ -4434,6 +4434,7 @@ static void init_proc_e500 (CPUPPCState *env, int version) { uint32_t tlbncfg[2]; uint64_t ivor_mask = 0x0000000F0000FFFFULL; + uint64_t ivpr_mask = 0xFFFF0000ULL; uint32_t l1cfg0 = 0x3800 /* 8 ways */ | 0x0020; /* 32 kb */ #if !defined(CONFIG_USER_ONLY) @@ -4575,7 +4576,7 @@ static void init_proc_e500 (CPUPPCState *env, int version) } #endif - init_excp_e200(env); + init_excp_e200(env, ivpr_mask); /* Allocate hardware IRQ controller */ ppce500_irq_init(env); } From b81ccf8ae7f157e5b150243e27c2845c7c7b7256 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 20 Jun 2012 21:55:55 +0200 Subject: [PATCH 69/72] PPC: Add e5500 CPU target This patch adds e5500's CPU initialization to the TCG CPU initialization code. Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 96 +++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 98695ab239..d185aaa486 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4424,16 +4424,69 @@ static void init_proc_e300 (CPUPPCState *env) #define check_pow_e500mc check_pow_none #define init_proc_e500mc init_proc_e500mc +/* e5500 core */ +#define POWERPC_INSNS_e5500 (PPC_INSNS_BASE | PPC_ISEL | \ + PPC_WRTEE | PPC_RFDI | PPC_RFMCI | \ + PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ + PPC_FLOAT | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \ + PPC_FLOAT_STFIWX | PPC_WAIT | \ + PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC | \ + PPC_64B | PPC_POPCNTB | PPC_POPCNTWD) +#define POWERPC_INSNS2_e5500 (PPC2_BOOKE206 | PPC2_PRCNTL) +#define POWERPC_MSRM_e5500 (0x000000009402FB36ULL) +#define POWERPC_MMU_e5500 (POWERPC_MMU_BOOKE206) +#define POWERPC_EXCP_e5500 (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_e5500 (PPC_FLAGS_INPUT_BookE) +/* Fixme: figure out the correct flag for e5500 */ +#define POWERPC_BFDM_e5500 (bfd_mach_ppc_e500) +#define POWERPC_FLAG_e5500 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) +#define check_pow_e5500 check_pow_none +#define init_proc_e5500 init_proc_e5500 + +#if !defined(CONFIG_USER_ONLY) +static void spr_write_mas73(void *opaque, int sprn, int gprn) +{ + TCGv val = tcg_temp_new(); + tcg_gen_ext32u_tl(val, cpu_gpr[gprn]); + gen_store_spr(SPR_BOOKE_MAS3, val); + tcg_gen_shri_tl(val, gprn, 32); + gen_store_spr(SPR_BOOKE_MAS7, val); + tcg_temp_free(val); +} + +static void spr_read_mas73(void *opaque, int gprn, int sprn) +{ + TCGv mas7 = tcg_temp_new(); + TCGv mas3 = tcg_temp_new(); + gen_load_spr(mas7, SPR_BOOKE_MAS7); + tcg_gen_shli_tl(mas7, mas7, 32); + gen_load_spr(mas3, SPR_BOOKE_MAS3); + tcg_gen_or_tl(cpu_gpr[gprn], mas3, mas7); + tcg_temp_free(mas3); + tcg_temp_free(mas7); +} + +static void spr_load_epr(void *opaque, int gprn, int sprn) +{ + gen_helper_load_epr(cpu_gpr[gprn], cpu_env); +} + +#endif + enum fsl_e500_version { fsl_e500v1, fsl_e500v2, fsl_e500mc, + fsl_e5500, }; static void init_proc_e500 (CPUPPCState *env, int version) { uint32_t tlbncfg[2]; - uint64_t ivor_mask = 0x0000000F0000FFFFULL; + uint64_t ivor_mask; uint64_t ivpr_mask = 0xFFFF0000ULL; uint32_t l1cfg0 = 0x3800 /* 8 ways */ | 0x0020; /* 32 kb */ @@ -4448,8 +4501,16 @@ static void init_proc_e500 (CPUPPCState *env, int version) * complain when accessing them. * gen_spr_BookE(env, 0x0000000F0000FD7FULL); */ - if (version == fsl_e500mc) { - ivor_mask = 0x000003FE0000FFFFULL; + switch (version) { + case fsl_e500v1: + case fsl_e500v2: + default: + ivor_mask = 0x0000000F0000FFFFULL; + break; + case fsl_e500mc: + case fsl_e5500: + ivor_mask = 0x000003FE0000FFFFULL; + break; } gen_spr_BookE(env, ivor_mask); /* Processor identification */ @@ -4477,6 +4538,7 @@ static void init_proc_e500 (CPUPPCState *env, int version) tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16); break; case fsl_e500mc: + case fsl_e5500: tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512); tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64); break; @@ -4492,6 +4554,7 @@ static void init_proc_e500 (CPUPPCState *env, int version) env->icache_line_size = 32; break; case fsl_e500mc: + case fsl_e5500: env->dcache_line_size = 64; env->icache_line_size = 64; l1cfg0 |= 0x1000000; /* 64 byte cache block size */ @@ -4567,6 +4630,22 @@ static void init_proc_e500 (CPUPPCState *env, int version) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_booke206_mmucsr0, 0x00000000); + spr_register(env, SPR_BOOKE_EPR, "EPR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_load_epr, SPR_NOACCESS, + 0x00000000); + /* XXX better abstract into Emb.xxx features */ + if (version == fsl_e5500) { + spr_register(env, SPR_BOOKE_EPCR, "EPCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MAS7_MAS3, "MAS7_MAS3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_mas73, &spr_write_mas73, + 0x00000000); + ivpr_mask = (target_ulong)~0xFFFFULL; + } #if !defined(CONFIG_USER_ONLY) env->nb_tlb = 0; @@ -4596,6 +4675,13 @@ static void init_proc_e500mc(CPUPPCState *env) init_proc_e500(env, fsl_e500mc); } +#ifdef TARGET_PPC64 +static void init_proc_e5500(CPUPPCState *env) +{ + init_proc_e500(env, fsl_e5500); +} +#endif + /* Non-embedded PowerPC */ /* POWER : same as 601, without mfmsr, mfsr */ @@ -7134,6 +7220,7 @@ enum { CPU_POWERPC_e500v2_v22 = 0x80210022, CPU_POWERPC_e500v2_v30 = 0x80210030, CPU_POWERPC_e500mc = 0x80230020, + CPU_POWERPC_e5500 = 0x80240020, /* MPC85xx microcontrollers */ #define CPU_POWERPC_MPC8533 CPU_POWERPC_MPC8533_v11 #define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21 @@ -8528,6 +8615,9 @@ static const ppc_def_t ppc_defs[] = { /* PowerPC e500v2 v3.0 core */ POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2), POWERPC_DEF("e500mc", CPU_POWERPC_e500mc, e500mc), +#ifdef TARGET_PPC64 + POWERPC_DEF("e5500", CPU_POWERPC_e5500, e5500), +#endif /* PowerPC e500 microcontrollers */ /* MPC8533 */ POWERPC_DEF_SVR("MPC8533", From 91f477fd9c1a6ff73d57a4352d78bd49b5180e30 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 21 Jun 2012 13:39:48 +0200 Subject: [PATCH 70/72] PPC: Extract SPR dump generation into its own function This patch moves the debug #ifdef'ed SPR trace generation into its own function, so we can call it from multiple places. Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index d185aaa486..8ff47aebfb 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -55,28 +55,34 @@ PPC_IRQ_INIT_FN(e500); /* Generic callbacks: * do nothing but store/retrieve spr value */ +static void spr_load_dump_spr(int sprn) +{ +#ifdef PPC_DUMP_SPR_ACCESSES + TCGv_i32 t0 = tcg_const_i32(sprn); + gen_helper_load_dump_spr(t0); + tcg_temp_free_i32(t0); +#endif +} + static void spr_read_generic (void *opaque, int gprn, int sprn) { gen_load_spr(cpu_gpr[gprn], sprn); + spr_load_dump_spr(sprn); +} + +static void spr_store_dump_spr(int sprn) +{ #ifdef PPC_DUMP_SPR_ACCESSES - { - TCGv_i32 t0 = tcg_const_i32(sprn); - gen_helper_load_dump_spr(t0); - tcg_temp_free_i32(t0); - } + TCGv_i32 t0 = tcg_const_i32(sprn); + gen_helper_store_dump_spr(t0); + tcg_temp_free_i32(t0); #endif } static void spr_write_generic (void *opaque, int sprn, int gprn) { gen_store_spr(sprn, cpu_gpr[gprn]); -#ifdef PPC_DUMP_SPR_ACCESSES - { - TCGv_i32 t0 = tcg_const_i32(sprn); - gen_helper_store_dump_spr(t0); - tcg_temp_free_i32(t0); - } -#endif + spr_store_dump_spr(sprn); } #if !defined(CONFIG_USER_ONLY) From ba38ab8d429a326c2a9c30110df84f0cad441094 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 21 Jun 2012 14:01:06 +0200 Subject: [PATCH 71/72] PPC: BookE: Support 32 and 64 bit wide MAS2 The MAS registers on BookE are all 32 bit wide, except for MAS2, which can hold up to 64 bit on 64 bit capable CPUs. Reflect this in the SPR setting code, so that the guest can never write invalid values in them. Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 8ff47aebfb..e6580ff27c 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -86,6 +86,19 @@ static void spr_write_generic (void *opaque, int sprn, int gprn) } #if !defined(CONFIG_USER_ONLY) +static void spr_write_generic32(void *opaque, int sprn, int gprn) +{ +#ifdef TARGET_PPC64 + TCGv t0 = tcg_temp_new(); + tcg_gen_ext32u_tl(t0, cpu_gpr[gprn]); + gen_store_spr(sprn, t0); + tcg_temp_free(t0); + spr_store_dump_spr(sprn); +#else + spr_write_generic(opaque, sprn, gprn); +#endif +} + static void spr_write_clear (void *opaque, int sprn, int gprn) { TCGv t0 = tcg_temp_new(); @@ -1597,10 +1610,14 @@ static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask, /* TLB assist registers */ /* XXX : not implemented */ for (i = 0; i < 8; i++) { + void (*uea_write)(void *o, int sprn, int gprn) = &spr_write_generic32; + if (i == 2 && (mas_mask & (1 << i)) && (env->insns_flags & PPC_64B)) { + uea_write = &spr_write_generic; + } if (mas_mask & (1 << i)) { spr_register(env, mas_sprn[i], mas_names[i], SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, uea_write, 0x00000000); } } From 960916988b9ec45bb10400d892351f360b4aac96 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 21 Jun 2012 13:34:20 +0200 Subject: [PATCH 72/72] PPC: BookE206: Bump MAS2 to 64bit On 64bit capable systems, MAS2 can actually hold a 64bit virtual page address. So increase the mask for its EPN. Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 652a35a39f..ca2fc2198e 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -693,7 +693,7 @@ enum { #define MAS1_VALID 0x80000000 #define MAS2_EPN_SHIFT 12 -#define MAS2_EPN_MASK (0xfffff << MAS2_EPN_SHIFT) +#define MAS2_EPN_MASK (~0ULL << MAS2_EPN_SHIFT) #define MAS2_ACM_SHIFT 6 #define MAS2_ACM (1 << MAS2_ACM_SHIFT)