aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/op.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-ppc/op.c')
-rw-r--r--target-ppc/op.c327
1 files changed, 204 insertions, 123 deletions
diff --git a/target-ppc/op.c b/target-ppc/op.c
index 822c26769..c950579a1 100644
--- a/target-ppc/op.c
+++ b/target-ppc/op.c
@@ -22,6 +22,8 @@
#include "config.h"
#include "exec.h"
+#include "host-utils.h"
+#include "helper_regs.h"
#include "op_helper.h"
#define REG 0
@@ -120,7 +122,6 @@
#define REG 31
#include "op_template.h"
-
void OPPROTO op_print_mem_EA (void)
{
do_print_mem_EA(T0);
@@ -135,13 +136,6 @@ void OPPROTO op_set_Rc0 (void)
RETURN();
}
-/* Set Rc1 (for floating point arithmetic) */
-void OPPROTO op_set_Rc1 (void)
-{
- env->crf[1] = env->fpscr[7];
- RETURN();
-}
-
/* Constants load */
void OPPROTO op_reset_T0 (void)
{
@@ -180,7 +174,7 @@ void OPPROTO op_set_T1_64 (void)
#if 0 // unused
void OPPROTO op_set_T2 (void)
{
- T2 = PARAM1;
+ T2 = (uint32_t)PARAM1;
RETURN();
}
#endif
@@ -197,6 +191,12 @@ void OPPROTO op_move_T2_T0 (void)
RETURN();
}
+void OPPROTO op_moven_T2_T0 (void)
+{
+ T2 = ~T0;
+ RETURN();
+}
+
/* Generate exceptions */
void OPPROTO op_raise_exception_err (void)
{
@@ -285,13 +285,13 @@ void OPPROTO op_store_xer_bc (void)
void OPPROTO op_load_xer (void)
{
- do_load_xer();
+ T0 = hreg_load_xer(env);
RETURN();
}
void OPPROTO op_store_xer (void)
{
- do_store_xer();
+ hreg_store_xer(env, T0);
RETURN();
}
@@ -317,6 +317,20 @@ void OPPROTO op_store_sr (void)
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_load_slb (void)
+{
+ T0 = ppc_load_slb(env, T1);
+ RETURN();
+}
+
+void OPPROTO op_store_slb (void)
+{
+ ppc_store_slb(env, T1, T0);
+ RETURN();
+}
+#endif /* defined(TARGET_PPC64) */
+
void OPPROTO op_load_sdr1 (void)
{
T0 = env->sdr1;
@@ -345,31 +359,36 @@ void OPPROTO op_store_asr (void)
void OPPROTO op_load_msr (void)
{
- T0 = do_load_msr(env);
+ T0 = env->msr;
RETURN();
}
void OPPROTO op_store_msr (void)
{
- do_store_msr(env, T0);
+ do_store_msr();
RETURN();
}
-void OPPROTO op_update_riee (void)
+#if defined (TARGET_PPC64)
+void OPPROTO op_store_msr_32 (void)
{
- msr_ri = (T0 >> MSR_RI) & 1;
- msr_ee = (T0 >> MSR_EE) & 1;
+ T0 = (env->msr & ~0xFFFFFFFFULL) | (T0 & 0xFFFFFFFF);
+ do_store_msr();
RETURN();
}
+#endif
-#if defined (TARGET_PPC64)
-void OPPROTO op_store_msr_32 (void)
+void OPPROTO op_update_riee (void)
{
- ppc_store_msr_32(env, T0);
+ /* We don't call do_store_msr here as we won't trigger
+ * any special case nor change hflags
+ */
+ T0 &= (1 << MSR_RI) | (1 << MSR_EE);
+ env->msr &= ~(1 << MSR_RI) | (1 << MSR_EE);
+ env->msr |= T0;
RETURN();
}
#endif
-#endif
/* SPR */
void OPPROTO op_load_spr (void)
@@ -533,40 +552,108 @@ void OPPROTO op_store_dbatl (void)
#endif /* !defined(CONFIG_USER_ONLY) */
/* FPSCR */
-void OPPROTO op_load_fpscr (void)
+#ifdef CONFIG_SOFTFLOAT
+void OPPROTO op_reset_fpstatus (void)
{
- do_load_fpscr();
+ env->fp_status.float_exception_flags = 0;
RETURN();
}
+#endif
-void OPPROTO op_store_fpscr (void)
+void OPPROTO op_compute_fprf (void)
{
- do_store_fpscr(PARAM1);
+ do_compute_fprf(PARAM1);
+ RETURN();
+}
+
+#ifdef CONFIG_SOFTFLOAT
+void OPPROTO op_float_check_status (void)
+{
+ do_float_check_status();
RETURN();
}
+#else
+void OPPROTO op_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)
+ do_raise_exception_err(env->exception_index, env->error_code);
+ }
+ RETURN();
+}
+#endif
-void OPPROTO op_reset_scrfx (void)
+#if defined(WORDS_BIGENDIAN)
+#define WORD0 0
+#define WORD1 1
+#else
+#define WORD0 1
+#define WORD1 0
+#endif
+void OPPROTO op_load_fpscr_FT0 (void)
{
- env->fpscr[7] &= ~0x8;
+ /* The 32 MSB of the target fpr are undefined.
+ * They'll be zero...
+ */
+ union {
+ float64 d;
+ struct {
+ uint32_t u[2];
+ } s;
+ } u;
+
+ u.s.u[WORD0] = 0;
+ u.s.u[WORD1] = env->fpscr;
+ FT0 = u.d;
+ RETURN();
+}
+
+void OPPROTO op_set_FT0 (void)
+{
+ union {
+ float64 d;
+ struct {
+ uint32_t u[2];
+ } s;
+ } u;
+
+ u.s.u[WORD0] = 0;
+ u.s.u[WORD1] = PARAM1;
+ FT0 = u.d;
RETURN();
}
+#undef WORD0
+#undef WORD1
-/* crf operations */
-void OPPROTO op_getbit_T0 (void)
+void OPPROTO op_load_fpscr_T0 (void)
{
- T0 = (T0 >> PARAM1) & 1;
+ T0 = (env->fpscr >> PARAM1) & 0xF;
RETURN();
}
-void OPPROTO op_getbit_T1 (void)
+void OPPROTO op_load_fpcc (void)
{
- T1 = (T1 >> PARAM1) & 1;
+ T0 = fpscr_fpcc;
RETURN();
}
-void OPPROTO op_setcrfbit (void)
+void OPPROTO op_fpscr_resetbit (void)
{
- T1 = (T1 & PARAM1) | (T0 << PARAM2);
+ env->fpscr &= PARAM1;
+ RETURN();
+}
+
+void OPPROTO op_fpscr_setbit (void)
+{
+ do_fpscr_setbit(PARAM1);
+ RETURN();
+}
+
+void OPPROTO op_store_fpscr (void)
+{
+ do_store_fpscr(PARAM1);
RETURN();
}
@@ -766,26 +853,18 @@ void OPPROTO op_add (void)
void OPPROTO op_check_addo (void)
{
- if (likely(!(((uint32_t)T2 ^ (uint32_t)T1 ^ UINT32_MAX) &
- ((uint32_t)T2 ^ (uint32_t)T0) & (1UL << 31)))) {
- xer_ov = 0;
- } else {
- xer_ov = 1;
- xer_so = 1;
- }
+ xer_ov = (((uint32_t)T2 ^ (uint32_t)T1 ^ UINT32_MAX) &
+ ((uint32_t)T2 ^ (uint32_t)T0)) >> 31;
+ xer_so |= xer_ov;
RETURN();
}
#if defined(TARGET_PPC64)
void OPPROTO op_check_addo_64 (void)
{
- if (likely(!(((uint64_t)T2 ^ (uint64_t)T1 ^ UINT64_MAX) &
- ((uint64_t)T2 ^ (uint64_t)T0) & (1ULL << 63)))) {
- xer_ov = 0;
- } else {
- xer_ov = 1;
- xer_so = 1;
- }
+ xer_ov = (((uint64_t)T2 ^ (uint64_t)T1 ^ UINT64_MAX) &
+ ((uint64_t)T2 ^ (uint64_t)T0)) >> 63;
+ xer_so |= xer_ov;
RETURN();
}
#endif
@@ -841,6 +920,8 @@ void OPPROTO op_add_me (void)
T0 += xer_ca + (-1);
if (likely((uint32_t)T1 != 0))
xer_ca = 1;
+ else
+ xer_ca = 0;
RETURN();
}
@@ -850,6 +931,8 @@ void OPPROTO op_add_me_64 (void)
T0 += xer_ca + (-1);
if (likely((uint64_t)T1 != 0))
xer_ca = 1;
+ else
+ xer_ca = 0;
RETURN();
}
#endif
@@ -876,9 +959,9 @@ void OPPROTO op_add_ze (void)
/* divide word */
void OPPROTO op_divw (void)
{
- if (unlikely(((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) ||
+ if (unlikely(((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
(int32_t)T1 == 0)) {
- T0 = (int32_t)((-1) * ((uint32_t)T0 >> 31));
+ T0 = (int32_t)(UINT32_MAX * ((uint32_t)T0 >> 31));
} else {
T0 = (int32_t)T0 / (int32_t)T1;
}
@@ -888,9 +971,9 @@ void OPPROTO op_divw (void)
#if defined(TARGET_PPC64)
void OPPROTO op_divd (void)
{
- if (unlikely(((int64_t)T0 == INT64_MIN && (int64_t)T1 == -1) ||
+ if (unlikely(((int64_t)T0 == INT64_MIN && (int64_t)T1 == (int64_t)-1LL) ||
(int64_t)T1 == 0)) {
- T0 = (int64_t)((-1ULL) * ((uint64_t)T0 >> 63));
+ T0 = (int64_t)(UINT64_MAX * ((uint64_t)T0 >> 63));
} else {
T0 = (int64_t)T0 / (int64_t)T1;
}
@@ -961,7 +1044,7 @@ void OPPROTO op_mulhd (void)
{
uint64_t tl, th;
- do_imul64(&tl, &th);
+ muls64(&tl, &th, T0, T1);
T0 = th;
RETURN();
}
@@ -979,7 +1062,7 @@ void OPPROTO op_mulhdu (void)
{
uint64_t tl, th;
- do_mul64(&tl, &th);
+ mulu64(&tl, &th, T0, T1);
T0 = th;
RETURN();
}
@@ -1061,32 +1144,6 @@ void OPPROTO op_subf (void)
RETURN();
}
-void OPPROTO op_check_subfo (void)
-{
- if (likely(!(((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) &
- ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)))) {
- xer_ov = 0;
- } else {
- xer_ov = 1;
- xer_so = 1;
- }
- RETURN();
-}
-
-#if defined(TARGET_PPC64)
-void OPPROTO op_check_subfo_64 (void)
-{
- if (likely(!(((uint64_t)(~T2) ^ (uint64_t)T1 ^ UINT64_MAX) &
- ((uint64_t)(~T2) ^ (uint64_t)T0) & (1ULL << 63)))) {
- xer_ov = 0;
- } else {
- xer_ov = 1;
- xer_so = 1;
- }
- RETURN();
-}
-#endif
-
/* subtract from carrying */
void OPPROTO op_check_subfc (void)
{
@@ -1140,7 +1197,7 @@ void OPPROTO op_subfic (void)
#if defined(TARGET_PPC64)
void OPPROTO op_subfic_64 (void)
{
- T0 = PARAM1 + ~T0 + 1;
+ T0 = (int64_t)PARAM1 + ~T0 + 1;
if ((uint64_t)T0 <= (uint64_t)PARAM1) {
xer_ca = 1;
} else {
@@ -1154,8 +1211,10 @@ void OPPROTO op_subfic_64 (void)
void OPPROTO op_subfme (void)
{
T0 = ~T0 + xer_ca - 1;
- if (likely((uint32_t)T0 != (uint32_t)-1))
+ if (likely((uint32_t)T0 != UINT32_MAX))
xer_ca = 1;
+ else
+ xer_ca = 0;
RETURN();
}
@@ -1163,8 +1222,10 @@ void OPPROTO op_subfme (void)
void OPPROTO op_subfme_64 (void)
{
T0 = ~T0 + xer_ca - 1;
- if (likely((uint64_t)T0 != (uint64_t)-1))
+ if (likely((uint64_t)T0 != UINT64_MAX))
xer_ca = 1;
+ else
+ xer_ca = 0;
RETURN();
}
#endif
@@ -1382,42 +1443,41 @@ void OPPROTO op_andc (void)
/* andi. */
void OPPROTO op_andi_T0 (void)
{
- T0 &= PARAM1;
+ T0 &= (uint32_t)PARAM1;
RETURN();
}
void OPPROTO op_andi_T1 (void)
{
- T1 &= PARAM1;
+ T1 &= (uint32_t)PARAM1;
RETURN();
}
#if defined(TARGET_PPC64)
void OPPROTO op_andi_T0_64 (void)
{
- T0 &= ((uint64_t)PARAM1 << 32) | PARAM2;
+ T0 &= ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
RETURN();
}
void OPPROTO op_andi_T1_64 (void)
{
- T1 &= ((uint64_t)PARAM1 << 32) | PARAM2;
+ T1 &= ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
RETURN();
}
#endif
-
/* count leading zero */
void OPPROTO op_cntlzw (void)
{
- T0 = _do_cntlzw(T0);
+ do_cntlzw();
RETURN();
}
#if defined(TARGET_PPC64)
void OPPROTO op_cntlzd (void)
{
- T0 = _do_cntlzd(T0);
+ do_cntlzd();
RETURN();
}
#endif
@@ -1490,7 +1550,7 @@ void OPPROTO op_orc (void)
/* ori */
void OPPROTO op_ori (void)
{
- T0 |= PARAM1;
+ T0 |= (uint32_t)PARAM1;
RETURN();
}
@@ -1504,7 +1564,7 @@ void OPPROTO op_xor (void)
/* xori */
void OPPROTO op_xori (void)
{
- T0 ^= PARAM1;
+ T0 ^= (uint32_t)PARAM1;
RETURN();
}
@@ -1638,6 +1698,12 @@ void OPPROTO op_sli_T0 (void)
RETURN();
}
+void OPPROTO op_sli_T1 (void)
+{
+ T1 = T1 << PARAM1;
+ RETURN();
+}
+
void OPPROTO op_srl_T0_T1 (void)
{
T0 = (uint32_t)T0 >> T1;
@@ -1684,28 +1750,44 @@ void OPPROTO op_srli_T1_64 (void)
/* fadd - fadd. */
void OPPROTO op_fadd (void)
{
+#if USE_PRECISE_EMULATION
+ do_fadd();
+#else
FT0 = float64_add(FT0, FT1, &env->fp_status);
+#endif
RETURN();
}
/* fsub - fsub. */
void OPPROTO op_fsub (void)
{
+#if USE_PRECISE_EMULATION
+ do_fsub();
+#else
FT0 = float64_sub(FT0, FT1, &env->fp_status);
+#endif
RETURN();
}
/* fmul - fmul. */
void OPPROTO op_fmul (void)
{
+#if USE_PRECISE_EMULATION
+ do_fmul();
+#else
FT0 = float64_mul(FT0, FT1, &env->fp_status);
+#endif
RETURN();
}
/* fdiv - fdiv. */
void OPPROTO op_fdiv (void)
{
+#if USE_PRECISE_EMULATION
+ do_fdiv();
+#else
FT0 = float64_div(FT0, FT1, &env->fp_status);
+#endif
RETURN();
}
@@ -1787,7 +1869,11 @@ void OPPROTO op_fnmsub (void)
/* frsp - frsp. */
void OPPROTO op_frsp (void)
{
+#if USE_PRECISE_EMULATION
+ do_frsp();
+#else
FT0 = float64_to_float32(FT0, &env->fp_status);
+#endif
RETURN();
}
@@ -1901,13 +1987,16 @@ void OPPROTO op_fneg (void)
#define MEMSUFFIX _kernel
#include "op_helper.h"
#include "op_mem.h"
+#define MEMSUFFIX _hypv
+#include "op_helper.h"
+#include "op_mem.h"
#endif
/* Special op to check and maybe clear reservation */
void OPPROTO op_check_reservation (void)
{
if ((uint32_t)env->reserve == (uint32_t)(T0 & ~0x00000003))
- env->reserve = -1;
+ env->reserve = (target_ulong)-1ULL;
RETURN();
}
@@ -1915,7 +2004,7 @@ void OPPROTO op_check_reservation (void)
void OPPROTO op_check_reservation_64 (void)
{
if ((uint64_t)env->reserve == (uint64_t)(T0 & ~0x00000003))
- env->reserve = -1;
+ env->reserve = (target_ulong)-1ULL;
RETURN();
}
#endif
@@ -1940,9 +2029,7 @@ void OPPROTO op_rfid (void)
do_rfid();
RETURN();
}
-#endif
-#if defined(TARGET_PPC64H)
void OPPROTO op_hrfid (void)
{
do_hrfid();
@@ -2079,30 +2166,27 @@ void OPPROTO op_store_601_rtcu (void)
RETURN();
}
+void OPPROTO op_store_hid0_601 (void)
+{
+ do_store_hid0_601();
+ RETURN();
+}
+
void OPPROTO op_load_601_bat (void)
{
T0 = env->IBAT[PARAM1][PARAM2];
RETURN();
}
-#endif /* !defined(CONFIG_USER_ONLY) */
-/* 601 unified BATs store.
- * To avoid using specific MMU code for 601, we store BATs in
- * IBAT and DBAT simultaneously, then emulate unified BATs.
- */
-#if !defined(CONFIG_USER_ONLY)
void OPPROTO op_store_601_batl (void)
{
- int nr = PARAM1;
-
- env->IBAT[1][nr] = T0;
- env->DBAT[1][nr] = T0;
+ do_store_ibatl_601(env, PARAM1, T0);
RETURN();
}
void OPPROTO op_store_601_batu (void)
{
- do_store_601_batu(PARAM1);
+ do_store_ibatu_601(env, PARAM1, T0);
RETURN();
}
#endif /* !defined(CONFIG_USER_ONLY) */
@@ -2111,9 +2195,9 @@ void OPPROTO op_store_601_batu (void)
/* XXX: those micro-ops need tests ! */
void OPPROTO op_POWER_abs (void)
{
- if (T0 == INT32_MIN)
+ if ((int32_t)T0 == INT32_MIN)
T0 = INT32_MAX;
- else if (T0 < 0)
+ else if ((int32_t)T0 < 0)
T0 = -T0;
RETURN();
}
@@ -2223,7 +2307,7 @@ void OPPROTO op_POWER_nabso (void)
void OPPROTO op_POWER_rlmi (void)
{
T0 = rotl32(T0, T2) & PARAM1;
- T0 |= T1 & PARAM2;
+ T0 |= T1 & (uint32_t)PARAM2;
RETURN();
}
@@ -2256,7 +2340,7 @@ void OPPROTO op_POWER_sleq (void)
void OPPROTO op_POWER_sllq (void)
{
- uint32_t msk = -1;
+ uint32_t msk = UINT32_MAX;
msk = msk << (T1 & 0x1FUL);
if (T1 & 0x20UL)
@@ -2269,7 +2353,7 @@ void OPPROTO op_POWER_sllq (void)
void OPPROTO op_POWER_slq (void)
{
- uint32_t msk = -1, tmp;
+ uint32_t msk = UINT32_MAX, tmp;
msk = msk << (T1 & 0x1FUL);
if (T1 & 0x20UL)
@@ -2285,7 +2369,7 @@ void OPPROTO op_POWER_sraq (void)
{
env->spr[SPR_MQ] = rotl32(T0, 32 - (T1 & 0x1FUL));
if (T1 & 0x20UL)
- T0 = -1L;
+ T0 = UINT32_MAX;
else
T0 = (int32_t)T0 >> T1;
RETURN();
@@ -2420,12 +2504,6 @@ void OPPROTO op_405_mullhwu (void)
RETURN();
}
-void OPPROTO op_405_check_ov (void)
-{
- do_405_check_ov();
- RETURN();
-}
-
void OPPROTO op_405_check_sat (void)
{
do_405_check_sat();
@@ -2447,7 +2525,7 @@ void OPPROTO op_405_check_satu (void)
{
if (unlikely(T0 < T2)) {
/* Saturate result */
- T0 = -1;
+ T0 = UINT32_MAX;
}
RETURN();
}
@@ -2494,7 +2572,12 @@ void OPPROTO op_rfmci (void)
void OPPROTO op_wrte (void)
{
- msr_ee = T0 >> 16;
+ /* We don't call do_store_msr here as we won't trigger
+ * any special case nor change hflags
+ */
+ T0 &= 1 << MSR_EE;
+ env->msr &= ~(1 << MSR_EE);
+ env->msr |= T0;
RETURN();
}
@@ -2515,7 +2598,7 @@ void OPPROTO op_4xx_tlbsx_check (void)
int tmp;
tmp = xer_so;
- if (T0 != -1)
+ if ((int)T0 != -1)
tmp |= 0x02;
env->crf[0] = tmp;
RETURN();
@@ -2633,7 +2716,6 @@ void OPPROTO op_store_booke_tsr (void)
}
#endif /* !defined(CONFIG_USER_ONLY) */
-#if defined(TARGET_PPCEMB)
/* SPE extension */
void OPPROTO op_splatw_T1_64 (void)
{
@@ -3352,4 +3434,3 @@ void OPPROTO op_efdtsteq (void)
T0 = _do_efdtsteq(T0_64, T1_64);
RETURN();
}
-#endif /* defined(TARGET_PPCEMB) */