/*
* PowerPC emulation for qemu: main translation routines.
- *
+ *
* Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
#include "exec-all.h"
#include "disas.h"
+/* Include definitions for instructions classes and implementations flags */
//#define DO_SINGLE_STEP
//#define PPC_DEBUG_DISAS
//#define DEBUG_MEMORY_ACCESSES
//#define DO_PPC_STATISTICS
+/*****************************************************************************/
+/* Code translation helpers */
#if defined(USE_DIRECT_JUMP)
#define TBPARAM(x)
#else
#include "gen-op.h"
-static inline void gen_set_T0 (target_ulong val)
+static always_inline void gen_set_T0 (target_ulong val)
{
#if defined(TARGET_PPC64)
if (val >> 32)
gen_op_set_T0(val);
}
-static inline void gen_set_T1 (target_ulong val)
+static always_inline void gen_set_T1 (target_ulong val)
{
#if defined(TARGET_PPC64)
if (val >> 32)
NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
}; \
-static inline void func(int n) \
+static always_inline void func (int n) \
{ \
NAME ## _table[n](); \
}
NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
}; \
-static inline void func(int n) \
+static always_inline void func (int n) \
{ \
NAME ## _table[n](); \
}
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
}; \
-static inline void func(int n) \
+static always_inline void func (int n) \
{ \
NAME ## _table[n](); \
}
GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
-static inline void gen_op_store_T0_fpscri(int n, uint8_t param)
+static always_inline void gen_op_store_T0_fpscri (int n, uint8_t param)
{
gen_op_set_T0(param);
gen_op_store_T0_fpscr(n);
int sf_mode;
#endif
int fpu_enabled;
-#if defined(TARGET_PPCSPE)
+ int altivec_enabled;
+#if defined(TARGET_PPCEMB)
int spe_enabled;
#endif
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled;
+ int dcache_line_size;
} DisasContext;
struct opc_handler_t {
uint64_t type;
/* handler */
void (*handler)(DisasContext *ctx);
-#if defined(DO_PPC_STATISTICS)
+#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
const unsigned char *oname;
+#endif
+#if defined(DO_PPC_STATISTICS)
uint64_t count;
#endif
};
-static inline void gen_set_Rc0 (DisasContext *ctx)
+static always_inline void gen_set_Rc0 (DisasContext *ctx)
{
#if defined(TARGET_PPC64)
if (ctx->sf_mode)
gen_op_set_Rc0();
}
-static inline void gen_update_nip (DisasContext *ctx, target_ulong nip)
+static always_inline void gen_update_nip (DisasContext *ctx, target_ulong nip)
{
#if defined(TARGET_PPC64)
if (ctx->sf_mode)
gen_op_update_nip(nip);
}
-#define RET_EXCP(ctx, excp, error) \
+#define GEN_EXCP(ctx, excp, error) \
do { \
- if ((ctx)->exception == EXCP_NONE) { \
+ if ((ctx)->exception == POWERPC_EXCP_NONE) { \
gen_update_nip(ctx, (ctx)->nip); \
} \
gen_op_raise_exception_err((excp), (error)); \
ctx->exception = (excp); \
} while (0)
-#define RET_INVAL(ctx) \
-RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL)
+#define GEN_EXCP_INVAL(ctx) \
+GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM, \
+ POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL)
+
+#define GEN_EXCP_PRIVOPC(ctx) \
+GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM, \
+ POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_OPC)
+
+#define GEN_EXCP_PRIVREG(ctx) \
+GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM, \
+ POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG)
+
+#define GEN_EXCP_NO_FP(ctx) \
+GEN_EXCP(ctx, POWERPC_EXCP_FPU, 0)
-#define RET_PRIVOPC(ctx) \
-RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
+#define GEN_EXCP_NO_AP(ctx) \
+GEN_EXCP(ctx, POWERPC_EXCP_APU, 0)
-#define RET_PRIVREG(ctx) \
-RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
+#define GEN_EXCP_NO_VR(ctx) \
+GEN_EXCP(ctx, POWERPC_EXCP_VPU, 0)
/* Stop translation */
-static inline void RET_STOP (DisasContext *ctx)
+static always_inline void GEN_STOP (DisasContext *ctx)
{
gen_update_nip(ctx, ctx->nip);
- ctx->exception = EXCP_MTMSR;
+ ctx->exception = POWERPC_EXCP_STOP;
}
/* No need to update nip here, as execution flow will change */
-static inline void RET_CHG_FLOW (DisasContext *ctx)
+static always_inline void GEN_SYNC (DisasContext *ctx)
{
- ctx->exception = EXCP_MTMSR;
+ ctx->exception = POWERPC_EXCP_SYNC;
}
#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
const unsigned char *oname;
} opcode_t;
+/*****************************************************************************/
/*** Instruction decoding ***/
#define EXTRACT_HELPER(name, shift, nb) \
-static inline uint32_t name (uint32_t opcode) \
+static always_inline uint32_t name (uint32_t opcode) \
{ \
return (opcode >> (shift)) & ((1 << (nb)) - 1); \
}
#define EXTRACT_SHELPER(name, shift, nb) \
-static inline int32_t name (uint32_t opcode) \
+static always_inline int32_t name (uint32_t opcode) \
{ \
return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \
}
EXTRACT_HELPER(crbB, 11, 5);
/* SPR / TBL */
EXTRACT_HELPER(_SPR, 11, 10);
-static inline uint32_t SPR (uint32_t opcode)
+static always_inline uint32_t SPR (uint32_t opcode)
{
uint32_t sprn = _SPR(opcode);
/* Displacement */
EXTRACT_SHELPER(d, 0, 16);
/* Immediate address */
-static inline target_ulong LI (uint32_t opcode)
+static always_inline target_ulong LI (uint32_t opcode)
{
return (opcode >> 0) & 0x03FFFFFC;
}
-static inline uint32_t BD (uint32_t opcode)
+static always_inline uint32_t BD (uint32_t opcode)
{
return (opcode >> 0) & 0xFFFC;
}
EXTRACT_HELPER(LK, 0, 1);
/* Create a mask between <start> and <end> bits */
-static inline target_ulong MASK (uint32_t start, uint32_t end)
+static always_inline target_ulong MASK (uint32_t start, uint32_t end)
{
target_ulong ret;
return ret;
}
+/*****************************************************************************/
+/* PowerPC Instructions types definitions */
+enum {
+ PPC_NONE = 0x0000000000000000ULL,
+ /* PowerPC base instructions set */
+ PPC_INSNS_BASE = 0x0000000000000001ULL,
+ /* integer operations instructions */
+#define PPC_INTEGER PPC_INSNS_BASE
+ /* flow control instructions */
+#define PPC_FLOW PPC_INSNS_BASE
+ /* virtual memory instructions */
+#define PPC_MEM PPC_INSNS_BASE
+ /* ld/st with reservation instructions */
+#define PPC_RES PPC_INSNS_BASE
+ /* cache control instructions */
+#define PPC_CACHE PPC_INSNS_BASE
+ /* spr/msr access instructions */
+#define PPC_MISC PPC_INSNS_BASE
+ /* Optional floating point instructions */
+ PPC_FLOAT = 0x0000000000000002ULL,
+ PPC_FLOAT_FSQRT = 0x0000000000000004ULL,
+ PPC_FLOAT_FRES = 0x0000000000000008ULL,
+ PPC_FLOAT_FRSQRTE = 0x0000000000000010ULL,
+ PPC_FLOAT_FSEL = 0x0000000000000020ULL,
+ PPC_FLOAT_STFIWX = 0x0000000000000040ULL,
+ /* external control instructions */
+ PPC_EXTERN = 0x0000000000000080ULL,
+ /* segment register access instructions */
+ PPC_SEGMENT = 0x0000000000000100ULL,
+ /* Optional cache control instruction */
+ PPC_CACHE_DCBA = 0x0000000000000200ULL,
+ /* Optional memory control instructions */
+ PPC_MEM_TLBIA = 0x0000000000000400ULL,
+ PPC_MEM_TLBIE = 0x0000000000000800ULL,
+ PPC_MEM_TLBSYNC = 0x0000000000001000ULL,
+ /* eieio & sync */
+ PPC_MEM_SYNC = 0x0000000000002000ULL,
+ /* PowerPC 6xx TLB management instructions */
+ PPC_6xx_TLB = 0x0000000000004000ULL,
+ /* Altivec support */
+ PPC_ALTIVEC = 0x0000000000008000ULL,
+ /* Time base mftb instruction */
+ PPC_MFTB = 0x0000000000010000ULL,
+ /* Embedded PowerPC dedicated instructions */
+ PPC_EMB_COMMON = 0x0000000000020000ULL,
+ /* PowerPC 40x exception model */
+ PPC_40x_EXCP = 0x0000000000040000ULL,
+ /* PowerPC 40x TLB management instructions */
+ PPC_40x_TLB = 0x0000000000080000ULL,
+ /* PowerPC 405 Mac instructions */
+ PPC_405_MAC = 0x0000000000100000ULL,
+ /* PowerPC 440 specific instructions */
+ PPC_440_SPEC = 0x0000000000200000ULL,
+ /* Power-to-PowerPC bridge (601) */
+ PPC_POWER_BR = 0x0000000000400000ULL,
+ /* PowerPC 602 specific */
+ PPC_602_SPEC = 0x0000000000800000ULL,
+ /* Deprecated instructions */
+ /* Original POWER instruction set */
+ PPC_POWER = 0x0000000001000000ULL,
+ /* POWER2 instruction set extension */
+ PPC_POWER2 = 0x0000000002000000ULL,
+ /* Power RTC support */
+ PPC_POWER_RTC = 0x0000000004000000ULL,
+ /* 64 bits PowerPC instruction set */
+ PPC_64B = 0x0000000008000000ULL,
+ /* 64 bits hypervisor extensions */
+ PPC_64H = 0x0000000010000000ULL,
+ /* segment register access instructions for PowerPC 64 "bridge" */
+ PPC_SEGMENT_64B = 0x0000000020000000ULL,
+ /* BookE (embedded) PowerPC specification */
+ PPC_BOOKE = 0x0000000040000000ULL,
+ /* eieio */
+ PPC_MEM_EIEIO = 0x0000000080000000ULL,
+ /* e500 vector instructions */
+ PPC_E500_VECTOR = 0x0000000100000000ULL,
+ /* PowerPC 4xx dedicated instructions */
+ PPC_4xx_COMMON = 0x0000000200000000ULL,
+ /* PowerPC 2.03 specification extensions */
+ PPC_203 = 0x0000000400000000ULL,
+ /* PowerPC 2.03 SPE extension */
+ PPC_SPE = 0x0000000800000000ULL,
+ /* PowerPC 2.03 SPE floating-point extension */
+ PPC_SPEFPU = 0x0000001000000000ULL,
+ /* SLB management */
+ PPC_SLBI = 0x0000002000000000ULL,
+ /* PowerPC 40x ibct instructions */
+ PPC_40x_ICBT = 0x0000004000000000ULL,
+ /* PowerPC 74xx TLB management instructions */
+ PPC_74xx_TLB = 0x0000008000000000ULL,
+ /* More BookE (embedded) instructions... */
+ PPC_BOOKE_EXT = 0x0000010000000000ULL,
+ /* rfmci is not implemented in all BookE PowerPC */
+ PPC_RFMCI = 0x0000020000000000ULL,
+ /* user-mode DCR access, implemented in PowerPC 460 */
+ PPC_DCRUX = 0x0000040000000000ULL,
+ /* New floating-point extensions (PowerPC 2.0x) */
+ PPC_FLOAT_EXT = 0x0000080000000000ULL,
+ /* New wait instruction (PowerPC 2.0x) */
+ PPC_WAIT = 0x0000100000000000ULL,
+ /* New 64 bits extensions (PowerPC 2.0x) */
+ PPC_64BX = 0x0000200000000000ULL,
+ /* dcbz instruction with fixed cache line size */
+ PPC_CACHE_DCBZ = 0x0000400000000000ULL,
+ /* dcbz instruction with tunable cache line size */
+ PPC_CACHE_DCBZT = 0x0000800000000000ULL,
+};
+
+/*****************************************************************************/
+/* PowerPC instructions table */
#if HOST_LONG_BITS == 64
#define OPC_ALIGN 8
#else
/* Invalid instruction */
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
{
- RET_INVAL(ctx);
+ GEN_EXCP_INVAL(ctx);
}
static opc_handler_t invalid_handler = {
#endif
/* add add. addo addo. */
-static inline void gen_op_addo (void)
+static always_inline void gen_op_addo (void)
{
gen_op_move_T2_T0();
gen_op_add();
}
#if defined(TARGET_PPC64)
#define gen_op_add_64 gen_op_add
-static inline void gen_op_addo_64 (void)
+static always_inline void gen_op_addo_64 (void)
{
gen_op_move_T2_T0();
gen_op_add();
#endif
GEN_INT_ARITH2_64 (add, 0x1F, 0x0A, 0x08, PPC_INTEGER);
/* addc addc. addco addco. */
-static inline void gen_op_addc (void)
+static always_inline void gen_op_addc (void)
{
gen_op_move_T2_T0();
gen_op_add();
gen_op_check_addc();
}
-static inline void gen_op_addco (void)
+static always_inline void gen_op_addco (void)
{
gen_op_move_T2_T0();
gen_op_add();
gen_op_check_addo();
}
#if defined(TARGET_PPC64)
-static inline void gen_op_addc_64 (void)
+static always_inline void gen_op_addc_64 (void)
{
gen_op_move_T2_T0();
gen_op_add();
gen_op_check_addc_64();
}
-static inline void gen_op_addco_64 (void)
+static always_inline void gen_op_addco_64 (void)
{
gen_op_move_T2_T0();
gen_op_add();
#endif
GEN_INT_ARITH2_64 (addc, 0x1F, 0x0A, 0x00, PPC_INTEGER);
/* adde adde. addeo addeo. */
-static inline void gen_op_addeo (void)
+static always_inline void gen_op_addeo (void)
{
gen_op_move_T2_T0();
gen_op_adde();
gen_op_check_addo();
}
#if defined(TARGET_PPC64)
-static inline void gen_op_addeo_64 (void)
+static always_inline void gen_op_addeo_64 (void)
{
gen_op_move_T2_T0();
gen_op_adde_64();
#endif
GEN_INT_ARITH2_64 (adde, 0x1F, 0x0A, 0x04, PPC_INTEGER);
/* addme addme. addmeo addmeo. */
-static inline void gen_op_addme (void)
+static always_inline void gen_op_addme (void)
{
gen_op_move_T1_T0();
gen_op_add_me();
}
#if defined(TARGET_PPC64)
-static inline void gen_op_addme_64 (void)
+static always_inline void gen_op_addme_64 (void)
{
gen_op_move_T1_T0();
gen_op_add_me_64();
#endif
GEN_INT_ARITH1_64 (addme, 0x1F, 0x0A, 0x07, PPC_INTEGER);
/* addze addze. addzeo addzeo. */
-static inline void gen_op_addze (void)
+static always_inline void gen_op_addze (void)
{
gen_op_move_T2_T0();
gen_op_add_ze();
gen_op_check_addc();
}
-static inline void gen_op_addzeo (void)
+static always_inline void gen_op_addzeo (void)
{
gen_op_move_T2_T0();
gen_op_add_ze();
gen_op_check_addo();
}
#if defined(TARGET_PPC64)
-static inline void gen_op_addze_64 (void)
+static always_inline void gen_op_addze_64 (void)
{
gen_op_move_T2_T0();
gen_op_add_ze();
gen_op_check_addc_64();
}
-static inline void gen_op_addzeo_64 (void)
+static always_inline void gen_op_addzeo_64 (void)
{
gen_op_move_T2_T0();
gen_op_add_ze();
/* neg neg. nego nego. */
GEN_INT_ARITH1_64 (neg, 0x1F, 0x08, 0x03, PPC_INTEGER);
/* subf subf. subfo subfo. */
-static inline void gen_op_subfo (void)
+static always_inline void gen_op_subfo (void)
{
gen_op_move_T2_T0();
gen_op_subf();
}
#if defined(TARGET_PPC64)
#define gen_op_subf_64 gen_op_subf
-static inline void gen_op_subfo_64 (void)
+static always_inline void gen_op_subfo_64 (void)
{
gen_op_move_T2_T0();
gen_op_subf();
#endif
GEN_INT_ARITH2_64 (subf, 0x1F, 0x08, 0x01, PPC_INTEGER);
/* subfc subfc. subfco subfco. */
-static inline void gen_op_subfc (void)
+static always_inline void gen_op_subfc (void)
{
gen_op_subf();
gen_op_check_subfc();
}
-static inline void gen_op_subfco (void)
+static always_inline void gen_op_subfco (void)
{
gen_op_move_T2_T0();
gen_op_subf();
gen_op_check_subfo();
}
#if defined(TARGET_PPC64)
-static inline void gen_op_subfc_64 (void)
+static always_inline void gen_op_subfc_64 (void)
{
gen_op_subf();
gen_op_check_subfc_64();
}
-static inline void gen_op_subfco_64 (void)
+static always_inline void gen_op_subfco_64 (void)
{
gen_op_move_T2_T0();
gen_op_subf();
#endif
GEN_INT_ARITH2_64 (subfc, 0x1F, 0x08, 0x00, PPC_INTEGER);
/* subfe subfe. subfeo subfeo. */
-static inline void gen_op_subfeo (void)
+static always_inline void gen_op_subfeo (void)
{
gen_op_move_T2_T0();
gen_op_subfe();
}
#if defined(TARGET_PPC64)
#define gen_op_subfe_64 gen_op_subfe
-static inline void gen_op_subfeo_64 (void)
+static always_inline void gen_op_subfeo_64 (void)
{
gen_op_move_T2_T0();
gen_op_subfe_64();
else
#endif
gen_op_check_addc();
+ } else {
+ gen_op_clear_xer_ca();
}
gen_op_store_T0_gpr(rD(ctx->opcode));
gen_set_Rc0(ctx);
#if defined(TARGET_PPC64)
/* mulhd mulhd. */
-GEN_INT_ARITHN (mulhd, 0x1F, 0x09, 0x02, PPC_INTEGER);
+GEN_INT_ARITHN (mulhd, 0x1F, 0x09, 0x02, PPC_64B);
/* mulhdu mulhdu. */
-GEN_INT_ARITHN (mulhdu, 0x1F, 0x09, 0x00, PPC_INTEGER);
+GEN_INT_ARITHN (mulhdu, 0x1F, 0x09, 0x00, PPC_64B);
/* mulld mulld. mulldo mulldo. */
-GEN_INT_ARITH2 (mulld, 0x1F, 0x09, 0x07, PPC_INTEGER);
+GEN_INT_ARITH2 (mulld, 0x1F, 0x09, 0x07, PPC_64B);
/* divd divd. divdo divdo. */
-GEN_INT_ARITH2 (divd, 0x1F, 0x09, 0x0F, PPC_INTEGER);
+GEN_INT_ARITH2 (divd, 0x1F, 0x09, 0x0F, PPC_64B);
/* divdu divdu. divduo divduo. */
-GEN_INT_ARITH2 (divdu, 0x1F, 0x09, 0x0E, PPC_INTEGER);
+GEN_INT_ARITH2 (divdu, 0x1F, 0x09, 0x0E, PPC_64B);
#endif
/*** Integer comparison ***/
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
- if (ctx->sf_mode) \
+ if (ctx->sf_mode && (ctx->opcode & 0x00200000)) \
gen_op_##name##_64(); \
else \
gen_op_##name(); \
{
gen_op_load_gpr_T0(rA(ctx->opcode));
#if defined(TARGET_PPC64)
- if (ctx->sf_mode)
+ if (ctx->sf_mode && (ctx->opcode & 0x00200000))
gen_op_cmpi_64(SIMM(ctx->opcode));
else
#endif
{
gen_op_load_gpr_T0(rA(ctx->opcode));
#if defined(TARGET_PPC64)
- if (ctx->sf_mode)
+ if (ctx->sf_mode && (ctx->opcode & 0x00200000))
gen_op_cmpli_64(UIMM(ctx->opcode));
else
#endif
} else if (unlikely(Rc(ctx->opcode) != 0)) {
gen_op_load_gpr_T0(rs);
gen_set_Rc0(ctx);
+#if defined(TARGET_PPC64)
+ } else {
+ switch (rs) {
+ case 1:
+ /* Set process priority to low */
+ gen_op_store_pri(2);
+ break;
+ case 6:
+ /* Set process priority to medium-low */
+ gen_op_store_pri(3);
+ break;
+ case 2:
+ /* Set process priority to normal */
+ gen_op_store_pri(4);
+ break;
+#if !defined(CONFIG_USER_ONLY)
+ case 31:
+ if (ctx->supervisor > 0) {
+ /* Set process priority to very low */
+ gen_op_store_pri(1);
+ }
+ break;
+ case 5:
+ if (ctx->supervisor > 0) {
+ /* Set process priority to medium-hight */
+ gen_op_store_pri(5);
+ }
+ break;
+ case 3:
+ if (ctx->supervisor > 0) {
+ /* Set process priority to high */
+ gen_op_store_pri(6);
+ }
+ break;
+#if defined(TARGET_PPC64H)
+ case 7:
+ if (ctx->supervisor > 1) {
+ /* Set process priority to very high */
+ gen_op_store_pri(7);
+ }
+ break;
+#endif
+#endif
+ default:
+ /* nop */
+ break;
+ }
+#endif
}
}
GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
uint32_t mb, me, sh;
-
+
sh = SH(ctx->opcode);
mb = MB(ctx->opcode);
me = ME(ctx->opcode);
gen_##name(ctx, 1, 1); \
}
-static inline void gen_rldinm (DisasContext *ctx, uint32_t mb, uint32_t me,
- uint32_t sh)
+static always_inline void gen_andi_T0_64 (DisasContext *ctx, uint64_t mask)
+{
+ if (mask >> 32)
+ gen_op_andi_T0_64(mask >> 32, mask & 0xFFFFFFFF);
+ else
+ gen_op_andi_T0(mask);
+}
+
+static always_inline void gen_andi_T1_64 (DisasContext *ctx, uint64_t mask)
+{
+ if (mask >> 32)
+ gen_op_andi_T1_64(mask >> 32, mask & 0xFFFFFFFF);
+ else
+ gen_op_andi_T1(mask);
+}
+
+static always_inline void gen_rldinm (DisasContext *ctx, uint32_t mb,
+ uint32_t me, uint32_t sh)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
if (likely(sh == 0)) {
}
if (likely(mb == 0)) {
if (likely(me == 63)) {
- gen_op_rotli32_T0(sh);
+ gen_op_rotli64_T0(sh);
goto do_store;
} else if (likely(me == (63 - sh))) {
gen_op_sli_T0(sh);
}
} else if (likely(me == 63)) {
if (likely(sh == (64 - mb))) {
- gen_op_srli_T0(mb);
+ gen_op_srli_T0_64(mb);
goto do_store;
}
}
gen_op_rotli64_T0(sh);
do_mask:
- gen_op_andi_T0(MASK(mb, me));
+ gen_andi_T0_64(ctx, MASK(mb, me));
do_store:
gen_op_store_T0_gpr(rA(ctx->opcode));
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx);
}
/* rldicl - rldicl. */
-static inline void gen_rldicl (DisasContext *ctx, int mbn, int shn)
+static always_inline void gen_rldicl (DisasContext *ctx, int mbn, int shn)
{
uint32_t sh, mb;
}
GEN_PPC64_R4(rldicl, 0x1E, 0x00);
/* rldicr - rldicr. */
-static inline void gen_rldicr (DisasContext *ctx, int men, int shn)
+static always_inline void gen_rldicr (DisasContext *ctx, int men, int shn)
{
uint32_t sh, me;
}
GEN_PPC64_R4(rldicr, 0x1E, 0x02);
/* rldic - rldic. */
-static inline void gen_rldic (DisasContext *ctx, int mbn, int shn)
+static always_inline void gen_rldic (DisasContext *ctx, int mbn, int shn)
{
uint32_t sh, mb;
}
GEN_PPC64_R4(rldic, 0x1E, 0x04);
-static inline void gen_rldnm (DisasContext *ctx, uint32_t mb, uint32_t me)
+static always_inline void gen_rldnm (DisasContext *ctx, uint32_t mb,
+ uint32_t me)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_load_gpr_T1(rB(ctx->opcode));
gen_op_rotl64_T0_T1();
if (unlikely(mb != 0 || me != 63)) {
- gen_op_andi_T0(MASK(mb, me));
+ gen_andi_T0_64(ctx, MASK(mb, me));
}
gen_op_store_T0_gpr(rA(ctx->opcode));
if (unlikely(Rc(ctx->opcode) != 0))
}
/* rldcl - rldcl. */
-static inline void gen_rldcl (DisasContext *ctx, int mbn)
+static always_inline void gen_rldcl (DisasContext *ctx, int mbn)
{
uint32_t mb;
mb = MB(ctx->opcode) | (mbn << 5);
gen_rldnm(ctx, mb, 63);
}
-GEN_PPC64_R2(rldcl, 0x1E, 0x08)
+GEN_PPC64_R2(rldcl, 0x1E, 0x08);
/* rldcr - rldcr. */
-static inline void gen_rldcr (DisasContext *ctx, int men)
+static always_inline void gen_rldcr (DisasContext *ctx, int men)
{
uint32_t me;
me = MB(ctx->opcode) | (men << 5);
gen_rldnm(ctx, 0, me);
}
-GEN_PPC64_R2(rldcr, 0x1E, 0x09)
+GEN_PPC64_R2(rldcr, 0x1E, 0x09);
/* rldimi - rldimi. */
-static inline void gen_rldimi (DisasContext *ctx, int mbn, int shn)
+static always_inline void gen_rldimi (DisasContext *ctx, int mbn, int shn)
{
uint64_t mask;
uint32_t sh, mb;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_load_gpr_T1(rA(ctx->opcode));
- gen_op_rotli64_T0(SH(ctx->opcode));
+ gen_op_rotli64_T0(sh);
do_mask:
mask = MASK(mb, 63 - sh);
- gen_op_andi_T0(mask);
- gen_op_andi_T1(~mask);
+ gen_andi_T0_64(ctx, mask);
+ gen_andi_T1_64(ctx, ~mask);
gen_op_or();
do_store:
gen_op_store_T0_gpr(rA(ctx->opcode));
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx);
}
-GEN_PPC64_R4(rldimi, 0x1E, 0x06)
+GEN_PPC64_R4(rldimi, 0x1E, 0x06);
#endif
/*** Integer shift ***/
/* srad & srad. */
__GEN_LOGICAL2(srad, 0x1A, 0x18, PPC_64B);
/* sradi & sradi. */
-static inline void gen_sradi (DisasContext *ctx, int n)
+static always_inline void gen_sradi (DisasContext *ctx, int n)
{
uint64_t mask;
int sh, mb, me;
#endif
/*** Floating-Point arithmetic ***/
-#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \
-GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
+#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, type) \
+GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
gen_op_reset_scrfx(); \
gen_op_set_Rc1(); \
}
-#define GEN_FLOAT_ACB(name, op2) \
-_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0); \
-_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
+#define GEN_FLOAT_ACB(name, op2, type) \
+_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, type); \
+_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, type);
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
gen_op_reset_scrfx(); \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
gen_op_reset_scrfx(); \
_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \
_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
-#define GEN_FLOAT_B(name, op2, op3) \
-GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
+#define GEN_FLOAT_B(name, op2, op3, type) \
+GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
gen_op_reset_scrfx(); \
gen_op_set_Rc1(); \
}
-#define GEN_FLOAT_BS(name, op1, op2) \
-GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
+#define GEN_FLOAT_BS(name, op1, op2, type) \
+GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
gen_op_reset_scrfx(); \
/* fmul - fmuls */
GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
-/* fres */ /* XXX: not in 601 */
-GEN_FLOAT_BS(res, 0x3B, 0x18);
+/* fre */
+GEN_FLOAT_BS(re, 0x3F, 0x18, PPC_FLOAT_EXT);
+
+/* fres */
+GEN_FLOAT_BS(res, 0x3B, 0x18, PPC_FLOAT_FRES);
-/* frsqrte */ /* XXX: not in 601 */
-GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
+/* frsqrte */
+GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, PPC_FLOAT_FRSQRTE);
-/* fsel */ /* XXX: not in 601 */
-_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
+/* fsel */
+_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, PPC_FLOAT_FSEL);
/* fsub - fsubs */
GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
/* Optional: */
/* fsqrt */
-GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
+GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
{
if (unlikely(!ctx->fpu_enabled)) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
+ GEN_EXCP_NO_FP(ctx);
return;
}
gen_op_reset_scrfx();
gen_op_set_Rc1();
}
-GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
+GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
{
if (unlikely(!ctx->fpu_enabled)) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
+ GEN_EXCP_NO_FP(ctx);
return;
}
gen_op_reset_scrfx();
/*** Floating-Point multiply-and-add ***/
/* fmadd - fmadds */
-GEN_FLOAT_ACB(madd, 0x1D);
+GEN_FLOAT_ACB(madd, 0x1D, PPC_FLOAT);
/* fmsub - fmsubs */
-GEN_FLOAT_ACB(msub, 0x1C);
+GEN_FLOAT_ACB(msub, 0x1C, PPC_FLOAT);
/* fnmadd - fnmadds */
-GEN_FLOAT_ACB(nmadd, 0x1F);
+GEN_FLOAT_ACB(nmadd, 0x1F, PPC_FLOAT);
/* fnmsub - fnmsubs */
-GEN_FLOAT_ACB(nmsub, 0x1E);
+GEN_FLOAT_ACB(nmsub, 0x1E, PPC_FLOAT);
/*** Floating-Point round & convert ***/
/* fctiw */
-GEN_FLOAT_B(ctiw, 0x0E, 0x00);
+GEN_FLOAT_B(ctiw, 0x0E, 0x00, PPC_FLOAT);
/* fctiwz */
-GEN_FLOAT_B(ctiwz, 0x0F, 0x00);
+GEN_FLOAT_B(ctiwz, 0x0F, 0x00, PPC_FLOAT);
/* frsp */
-GEN_FLOAT_B(rsp, 0x0C, 0x00);
+GEN_FLOAT_B(rsp, 0x0C, 0x00, PPC_FLOAT);
#if defined(TARGET_PPC64)
/* fcfid */
-GEN_FLOAT_B(cfid, 0x0E, 0x1A);
+GEN_FLOAT_B(cfid, 0x0E, 0x1A, PPC_64B);
/* fctid */
-GEN_FLOAT_B(ctid, 0x0E, 0x19);
+GEN_FLOAT_B(ctid, 0x0E, 0x19, PPC_64B);
/* fctidz */
-GEN_FLOAT_B(ctidz, 0x0F, 0x19);
+GEN_FLOAT_B(ctidz, 0x0F, 0x19, PPC_64B);
#endif
+/* frin */
+GEN_FLOAT_B(rin, 0x08, 0x0C, PPC_FLOAT_EXT);
+/* friz */
+GEN_FLOAT_B(riz, 0x08, 0x0D, PPC_FLOAT_EXT);
+/* frip */
+GEN_FLOAT_B(rip, 0x08, 0x0E, PPC_FLOAT_EXT);
+/* frim */
+GEN_FLOAT_B(rim, 0x08, 0x0F, PPC_FLOAT_EXT);
+
/*** Floating-Point compare ***/
/* fcmpo */
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
{
if (unlikely(!ctx->fpu_enabled)) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
+ GEN_EXCP_NO_FP(ctx);
return;
}
gen_op_reset_scrfx();
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
{
if (unlikely(!ctx->fpu_enabled)) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
+ GEN_EXCP_NO_FP(ctx);
return;
}
gen_op_reset_scrfx();
/*** Floating-point move ***/
/* fabs */
-GEN_FLOAT_B(abs, 0x08, 0x08);
+GEN_FLOAT_B(abs, 0x08, 0x08, PPC_FLOAT);
/* fmr - fmr. */
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
{
if (unlikely(!ctx->fpu_enabled)) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
+ GEN_EXCP_NO_FP(ctx);
return;
}
gen_op_reset_scrfx();
}
/* fnabs */
-GEN_FLOAT_B(nabs, 0x08, 0x04);
+GEN_FLOAT_B(nabs, 0x08, 0x04, PPC_FLOAT);
/* fneg */
-GEN_FLOAT_B(neg, 0x08, 0x01);
+GEN_FLOAT_B(neg, 0x08, 0x01, PPC_FLOAT);
/*** Floating-Point status & ctrl register ***/
/* mcrfs */
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
{
if (unlikely(!ctx->fpu_enabled)) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
+ GEN_EXCP_NO_FP(ctx);
return;
}
gen_op_load_fpscr_T0(crfS(ctx->opcode));
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
{
if (unlikely(!ctx->fpu_enabled)) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
+ GEN_EXCP_NO_FP(ctx);
return;
}
gen_op_load_fpscr();
GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
{
uint8_t crb;
-
+
if (unlikely(!ctx->fpu_enabled)) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
+ GEN_EXCP_NO_FP(ctx);
return;
}
crb = crbD(ctx->opcode) >> 2;
GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
{
uint8_t crb;
-
+
if (unlikely(!ctx->fpu_enabled)) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
+ GEN_EXCP_NO_FP(ctx);
return;
}
crb = crbD(ctx->opcode) >> 2;
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
{
if (unlikely(!ctx->fpu_enabled)) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
+ GEN_EXCP_NO_FP(ctx);
return;
}
gen_op_load_fpr_FT0(rB(ctx->opcode));
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
{
if (unlikely(!ctx->fpu_enabled)) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
+ GEN_EXCP_NO_FP(ctx);
return;
}
gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
/*** Addressing modes ***/
/* Register indirect with immediate index : EA = (rA|0) + SIMM */
-static inline void gen_addr_imm_index (DisasContext *ctx, int maskl)
+static always_inline void gen_addr_imm_index (DisasContext *ctx,
+ target_long maskl)
{
target_long simm = SIMM(ctx->opcode);
- if (maskl)
- simm &= ~0x03;
+ simm &= ~maskl;
if (rA(ctx->opcode) == 0) {
gen_set_T0(simm);
} else {
#endif
}
-static inline void gen_addr_reg_index (DisasContext *ctx)
+static always_inline void gen_addr_reg_index (DisasContext *ctx)
{
if (rA(ctx->opcode) == 0) {
gen_op_load_gpr_T0(rB(ctx->opcode));
#endif
}
-static inline void gen_addr_register (DisasContext *ctx)
+static always_inline void gen_addr_register (DisasContext *ctx)
{
if (rA(ctx->opcode) == 0) {
gen_op_reset_T0();
#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
#if defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
+/* User mode only - 64 bits */
#define OP_LD_TABLE(width) \
static GenOpFunc *gen_op_l##width[] = { \
&gen_op_l##width##_raw, \
#define gen_op_stb_le_64_raw gen_op_stb_64_raw
#define gen_op_lbz_le_64_raw gen_op_lbz_64_raw
#else
+/* User mode only - 32 bits */
#define OP_LD_TABLE(width) \
static GenOpFunc *gen_op_l##width[] = { \
&gen_op_l##width##_raw, \
#define gen_op_lbz_le_raw gen_op_lbz_raw
#else
#if defined(TARGET_PPC64)
+#if defined(TARGET_PPC64H)
+/* Full system - 64 bits with hypervisor mode */
#define OP_LD_TABLE(width) \
static GenOpFunc *gen_op_l##width[] = { \
&gen_op_l##width##_user, \
&gen_op_l##width##_le_user, \
- &gen_op_l##width##_kernel, \
- &gen_op_l##width##_le_kernel, \
&gen_op_l##width##_64_user, \
&gen_op_l##width##_le_64_user, \
+ &gen_op_l##width##_kernel, \
+ &gen_op_l##width##_le_kernel, \
&gen_op_l##width##_64_kernel, \
&gen_op_l##width##_le_64_kernel, \
+ &gen_op_l##width##_hypv, \
+ &gen_op_l##width##_le_hypv, \
+ &gen_op_l##width##_64_hypv, \
+ &gen_op_l##width##_le_64_hypv, \
};
#define OP_ST_TABLE(width) \
static GenOpFunc *gen_op_st##width[] = { \
&gen_op_st##width##_user, \
&gen_op_st##width##_le_user, \
+ &gen_op_st##width##_64_user, \
+ &gen_op_st##width##_le_64_user, \
&gen_op_st##width##_kernel, \
&gen_op_st##width##_le_kernel, \
+ &gen_op_st##width##_64_kernel, \
+ &gen_op_st##width##_le_64_kernel, \
+ &gen_op_st##width##_hypv, \
+ &gen_op_st##width##_le_hypv, \
+ &gen_op_st##width##_64_hypv, \
+ &gen_op_st##width##_le_64_hypv, \
+};
+/* Byte access routine are endian safe */
+#define gen_op_stb_le_hypv gen_op_stb_64_hypv
+#define gen_op_lbz_le_hypv gen_op_lbz_64_hypv
+#define gen_op_stb_le_64_hypv gen_op_stb_64_hypv
+#define gen_op_lbz_le_64_hypv gen_op_lbz_64_hypv
+#else
+/* Full system - 64 bits */
+#define OP_LD_TABLE(width) \
+static GenOpFunc *gen_op_l##width[] = { \
+ &gen_op_l##width##_user, \
+ &gen_op_l##width##_le_user, \
+ &gen_op_l##width##_64_user, \
+ &gen_op_l##width##_le_64_user, \
+ &gen_op_l##width##_kernel, \
+ &gen_op_l##width##_le_kernel, \
+ &gen_op_l##width##_64_kernel, \
+ &gen_op_l##width##_le_64_kernel, \
+};
+#define OP_ST_TABLE(width) \
+static GenOpFunc *gen_op_st##width[] = { \
+ &gen_op_st##width##_user, \
+ &gen_op_st##width##_le_user, \
&gen_op_st##width##_64_user, \
&gen_op_st##width##_le_64_user, \
+ &gen_op_st##width##_kernel, \
+ &gen_op_st##width##_le_kernel, \
&gen_op_st##width##_64_kernel, \
&gen_op_st##width##_le_64_kernel, \
};
+#endif
/* Byte access routine are endian safe */
-#define gen_op_stb_le_64_user gen_op_stb_64_user
-#define gen_op_lbz_le_64_user gen_op_lbz_64_user
+#define gen_op_stb_le_64_user gen_op_stb_64_user
+#define gen_op_lbz_le_64_user gen_op_lbz_64_user
#define gen_op_stb_le_64_kernel gen_op_stb_64_kernel
#define gen_op_lbz_le_64_kernel gen_op_lbz_64_kernel
#else
+/* Full system - 32 bits */
#define OP_LD_TABLE(width) \
static GenOpFunc *gen_op_l##width[] = { \
&gen_op_l##width##_user, \
};
#endif
/* Byte access routine are endian safe */
-#define gen_op_stb_le_user gen_op_stb_user
-#define gen_op_lbz_le_user gen_op_lbz_user
+#define gen_op_stb_le_user gen_op_stb_user
+#define gen_op_lbz_le_user gen_op_lbz_user
#define gen_op_stb_le_kernel gen_op_stb_kernel
#define gen_op_lbz_le_kernel gen_op_lbz_kernel
#endif
{ \
if (unlikely(rA(ctx->opcode) == 0 || \
rA(ctx->opcode) == rD(ctx->opcode))) { \
- RET_INVAL(ctx); \
+ GEN_EXCP_INVAL(ctx); \
return; \
} \
if (type == PPC_64B) \
- gen_addr_imm_index(ctx, 1); \
+ gen_addr_imm_index(ctx, 0x03); \
else \
gen_addr_imm_index(ctx, 0); \
op_ldst(l##width); \
{ \
if (unlikely(rA(ctx->opcode) == 0 || \
rA(ctx->opcode) == rD(ctx->opcode))) { \
- RET_INVAL(ctx); \
+ GEN_EXCP_INVAL(ctx); \
return; \
} \
gen_addr_reg_index(ctx); \
if (Rc(ctx->opcode)) {
if (unlikely(rA(ctx->opcode) == 0 ||
rA(ctx->opcode) == rD(ctx->opcode))) {
- RET_INVAL(ctx);
+ GEN_EXCP_INVAL(ctx);
return;
}
}
- gen_addr_imm_index(ctx, 1);
+ gen_addr_imm_index(ctx, 0x03);
if (ctx->opcode & 0x02) {
/* lwa (lwau is undefined) */
op_ldst(lwa);
if (Rc(ctx->opcode))
gen_op_store_T0_gpr(rA(ctx->opcode));
}
+/* lq */
+GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVOPC(ctx);
+#else
+ int ra, rd;
+
+ /* Restore CPU state */
+ if (unlikely(ctx->supervisor == 0)) {
+ GEN_EXCP_PRIVOPC(ctx);
+ return;
+ }
+ ra = rA(ctx->opcode);
+ rd = rD(ctx->opcode);
+ if (unlikely((rd & 1) || rd == ra)) {
+ GEN_EXCP_INVAL(ctx);
+ return;
+ }
+ if (unlikely(ctx->mem_idx & 1)) {
+ /* Little-endian mode is not handled */
+ GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
+ return;
+ }
+ gen_addr_imm_index(ctx, 0x0F);
+ op_ldst(ld);
+ gen_op_store_T1_gpr(rd);
+ gen_op_addi(8);
+ op_ldst(ld);
+ gen_op_store_T1_gpr(rd + 1);
+#endif
+}
#endif
/*** Integer store ***/
GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \
{ \
if (unlikely(rA(ctx->opcode) == 0)) { \
- RET_INVAL(ctx); \
+ GEN_EXCP_INVAL(ctx); \
return; \
} \
if (type == PPC_64B) \
- gen_addr_imm_index(ctx, 1); \
+ gen_addr_imm_index(ctx, 0x03); \
else \
gen_addr_imm_index(ctx, 0); \
gen_op_load_gpr_T1(rS(ctx->opcode)); \
GEN_HANDLER(st##width##ux, 0x1F, opc2, opc3, 0x00000001, type) \
{ \
if (unlikely(rA(ctx->opcode) == 0)) { \
- RET_INVAL(ctx); \
+ GEN_EXCP_INVAL(ctx); \
return; \
} \
gen_addr_reg_index(ctx); \
OP_ST_TABLE(d);
GEN_STUX(d, 0x15, 0x05, PPC_64B);
GEN_STX(d, 0x15, 0x04, PPC_64B);
-GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000002, PPC_64B)
+GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B)
{
- if (Rc(ctx->opcode)) {
- if (unlikely(rA(ctx->opcode) == 0)) {
- RET_INVAL(ctx);
+ int rs;
+
+ rs = rS(ctx->opcode);
+ if ((ctx->opcode & 0x3) == 0x2) {
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVOPC(ctx);
+#else
+ /* stq */
+ if (unlikely(ctx->supervisor == 0)) {
+ GEN_EXCP_PRIVOPC(ctx);
+ return;
+ }
+ if (unlikely(rs & 1)) {
+ GEN_EXCP_INVAL(ctx);
+ return;
+ }
+ if (unlikely(ctx->mem_idx & 1)) {
+ /* Little-endian mode is not handled */
+ GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
return;
}
+ gen_addr_imm_index(ctx, 0x03);
+ gen_op_load_gpr_T1(rs);
+ op_ldst(std);
+ gen_op_addi(8);
+ gen_op_load_gpr_T1(rs + 1);
+ op_ldst(std);
+#endif
+ } else {
+ /* std / stdu */
+ if (Rc(ctx->opcode)) {
+ if (unlikely(rA(ctx->opcode) == 0)) {
+ GEN_EXCP_INVAL(ctx);
+ return;
+ }
+ }
+ gen_addr_imm_index(ctx, 0x03);
+ gen_op_load_gpr_T1(rs);
+ op_ldst(std);
+ if (Rc(ctx->opcode))
+ gen_op_store_T0_gpr(rA(ctx->opcode));
}
- gen_addr_imm_index(ctx, 1);
- gen_op_load_gpr_T1(rS(ctx->opcode));
- op_ldst(std);
- if (Rc(ctx->opcode))
- gen_op_store_T0_gpr(rA(ctx->opcode));
}
#endif
/*** Integer load and store with byte reverse ***/
/*** Integer load and store multiple ***/
#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
-#if defined(TARGET_PPC64)
#if defined(CONFIG_USER_ONLY)
+/* User-mode only */
static GenOpFunc1 *gen_op_lmw[] = {
&gen_op_lmw_raw,
&gen_op_lmw_le_raw,
+#if defined(TARGET_PPC64)
&gen_op_lmw_64_raw,
&gen_op_lmw_le_64_raw,
+#endif
};
static GenOpFunc1 *gen_op_stmw[] = {
+ &gen_op_stmw_raw,
+ &gen_op_stmw_le_raw,
+#if defined(TARGET_PPC64)
&gen_op_stmw_64_raw,
&gen_op_stmw_le_64_raw,
+#endif
};
#else
+#if defined(TARGET_PPC64)
+/* Full system - 64 bits mode */
static GenOpFunc1 *gen_op_lmw[] = {
&gen_op_lmw_user,
&gen_op_lmw_le_user,
- &gen_op_lmw_kernel,
- &gen_op_lmw_le_kernel,
&gen_op_lmw_64_user,
&gen_op_lmw_le_64_user,
+ &gen_op_lmw_kernel,
+ &gen_op_lmw_le_kernel,
&gen_op_lmw_64_kernel,
&gen_op_lmw_le_64_kernel,
+#if defined(TARGET_PPC64H)
+ &gen_op_lmw_hypv,
+ &gen_op_lmw_le_hypv,
+ &gen_op_lmw_64_hypv,
+ &gen_op_lmw_le_64_hypv,
+#endif
};
static GenOpFunc1 *gen_op_stmw[] = {
&gen_op_stmw_user,
&gen_op_stmw_le_user,
- &gen_op_stmw_kernel,
- &gen_op_stmw_le_kernel,
&gen_op_stmw_64_user,
&gen_op_stmw_le_64_user,
+ &gen_op_stmw_kernel,
+ &gen_op_stmw_le_kernel,
&gen_op_stmw_64_kernel,
&gen_op_stmw_le_64_kernel,
-};
+#if defined(TARGET_PPC64H)
+ &gen_op_stmw_hypv,
+ &gen_op_stmw_le_hypv,
+ &gen_op_stmw_64_hypv,
+ &gen_op_stmw_le_64_hypv,
#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-static GenOpFunc1 *gen_op_lmw[] = {
- &gen_op_lmw_raw,
- &gen_op_lmw_le_raw,
-};
-static GenOpFunc1 *gen_op_stmw[] = {
- &gen_op_stmw_raw,
- &gen_op_stmw_le_raw,
};
#else
+/* Full system - 32 bits mode */
static GenOpFunc1 *gen_op_lmw[] = {
&gen_op_lmw_user,
&gen_op_lmw_le_user,
/*** Integer load and store strings ***/
#define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)
#define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)
-#if defined(TARGET_PPC64)
#if defined(CONFIG_USER_ONLY)
+/* User-mode only */
static GenOpFunc1 *gen_op_lswi[] = {
&gen_op_lswi_raw,
&gen_op_lswi_le_raw,
+#if defined(TARGET_PPC64)
&gen_op_lswi_64_raw,
&gen_op_lswi_le_64_raw,
+#endif
};
static GenOpFunc3 *gen_op_lswx[] = {
&gen_op_lswx_raw,
&gen_op_lswx_le_raw,
+#if defined(TARGET_PPC64)
&gen_op_lswx_64_raw,
&gen_op_lswx_le_64_raw,
+#endif
};
static GenOpFunc1 *gen_op_stsw[] = {
&gen_op_stsw_raw,
&gen_op_stsw_le_raw,
+#if defined(TARGET_PPC64)
&gen_op_stsw_64_raw,
&gen_op_stsw_le_64_raw,
+#endif
};
#else
+#if defined(TARGET_PPC64)
+/* Full system - 64 bits mode */
static GenOpFunc1 *gen_op_lswi[] = {
&gen_op_lswi_user,
&gen_op_lswi_le_user,
- &gen_op_lswi_kernel,
- &gen_op_lswi_le_kernel,
&gen_op_lswi_64_user,
&gen_op_lswi_le_64_user,
+ &gen_op_lswi_kernel,
+ &gen_op_lswi_le_kernel,
&gen_op_lswi_64_kernel,
&gen_op_lswi_le_64_kernel,
+#if defined(TARGET_PPC64H)
+ &gen_op_lswi_hypv,
+ &gen_op_lswi_le_hypv,
+ &gen_op_lswi_64_hypv,
+ &gen_op_lswi_le_64_hypv,
+#endif
};
static GenOpFunc3 *gen_op_lswx[] = {
&gen_op_lswx_user,
&gen_op_lswx_le_user,
- &gen_op_lswx_kernel,
- &gen_op_lswx_le_kernel,
&gen_op_lswx_64_user,
&gen_op_lswx_le_64_user,
+ &gen_op_lswx_kernel,
+ &gen_op_lswx_le_kernel,
&gen_op_lswx_64_kernel,
&gen_op_lswx_le_64_kernel,
+#if defined(TARGET_PPC64H)
+ &gen_op_lswx_hypv,
+ &gen_op_lswx_le_hypv,
+ &gen_op_lswx_64_hypv,
+ &gen_op_lswx_le_64_hypv,
+#endif
};
static GenOpFunc1 *gen_op_stsw[] = {
&gen_op_stsw_user,
&gen_op_stsw_le_user,
- &gen_op_stsw_kernel,
- &gen_op_stsw_le_kernel,
&gen_op_stsw_64_user,
&gen_op_stsw_le_64_user,
+ &gen_op_stsw_kernel,
+ &gen_op_stsw_le_kernel,
&gen_op_stsw_64_kernel,
&gen_op_stsw_le_64_kernel,
-};
+#if defined(TARGET_PPC64H)
+ &gen_op_stsw_hypv,
+ &gen_op_stsw_le_hypv,
+ &gen_op_stsw_64_hypv,
+ &gen_op_stsw_le_64_hypv,
#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-static GenOpFunc1 *gen_op_lswi[] = {
- &gen_op_lswi_raw,
- &gen_op_lswi_le_raw,
-};
-static GenOpFunc3 *gen_op_lswx[] = {
- &gen_op_lswx_raw,
- &gen_op_lswx_le_raw,
-};
-static GenOpFunc1 *gen_op_stsw[] = {
- &gen_op_stsw_raw,
- &gen_op_stsw_le_raw,
};
#else
+/* Full system - 32 bits mode */
static GenOpFunc1 *gen_op_lswi[] = {
&gen_op_lswi_user,
&gen_op_lswi_le_user,
if (unlikely(((start + nr) > 32 &&
start <= ra && (start + nr - 32) > ra) ||
((start + nr) <= 32 && start <= ra && (start + nr) > ra))) {
- RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
+ GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_LSWX);
return;
}
/* NIP cannot be restored if the memory exception comes from an helper */
GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
{
/* NIP cannot be restored if the memory exception comes from an helper */
- gen_update_nip(ctx, ctx->nip - 4);
+ gen_update_nip(ctx, ctx->nip - 4);
gen_addr_reg_index(ctx);
gen_op_load_xer_bc();
op_ldsts(stsw, rS(ctx->opcode));
/*** Memory synchronisation ***/
/* eieio */
-GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM_EIEIO)
+GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FFF801, PPC_MEM_EIEIO)
{
}
/* isync */
-GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FF0801, PPC_MEM)
+GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM)
{
+ GEN_STOP(ctx);
}
#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
-#if defined(TARGET_PPC64)
#if defined(CONFIG_USER_ONLY)
+/* User-mode only */
static GenOpFunc *gen_op_lwarx[] = {
&gen_op_lwarx_raw,
&gen_op_lwarx_le_raw,
+#if defined(TARGET_PPC64)
&gen_op_lwarx_64_raw,
&gen_op_lwarx_le_64_raw,
+#endif
};
static GenOpFunc *gen_op_stwcx[] = {
&gen_op_stwcx_raw,
&gen_op_stwcx_le_raw,
+#if defined(TARGET_PPC64)
&gen_op_stwcx_64_raw,
&gen_op_stwcx_le_64_raw,
+#endif
};
#else
+#if defined(TARGET_PPC64)
+/* Full system - 64 bits mode */
static GenOpFunc *gen_op_lwarx[] = {
&gen_op_lwarx_user,
&gen_op_lwarx_le_user,
- &gen_op_lwarx_kernel,
- &gen_op_lwarx_le_kernel,
&gen_op_lwarx_64_user,
&gen_op_lwarx_le_64_user,
+ &gen_op_lwarx_kernel,
+ &gen_op_lwarx_le_kernel,
&gen_op_lwarx_64_kernel,
&gen_op_lwarx_le_64_kernel,
+#if defined(TARGET_PPC64H)
+ &gen_op_lwarx_hypv,
+ &gen_op_lwarx_le_hypv,
+ &gen_op_lwarx_64_hypv,
+ &gen_op_lwarx_le_64_hypv,
+#endif
};
static GenOpFunc *gen_op_stwcx[] = {
&gen_op_stwcx_user,
&gen_op_stwcx_le_user,
- &gen_op_stwcx_kernel,
- &gen_op_stwcx_le_kernel,
&gen_op_stwcx_64_user,
&gen_op_stwcx_le_64_user,
+ &gen_op_stwcx_kernel,
+ &gen_op_stwcx_le_kernel,
&gen_op_stwcx_64_kernel,
&gen_op_stwcx_le_64_kernel,
-};
+#if defined(TARGET_PPC64H)
+ &gen_op_stwcx_hypv,
+ &gen_op_stwcx_le_hypv,
+ &gen_op_stwcx_64_hypv,
+ &gen_op_stwcx_le_64_hypv,
#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-static GenOpFunc *gen_op_lwarx[] = {
- &gen_op_lwarx_raw,
- &gen_op_lwarx_le_raw,
-};
-static GenOpFunc *gen_op_stwcx[] = {
- &gen_op_stwcx_raw,
- &gen_op_stwcx_le_raw,
};
#else
+/* Full system - 32 bits mode */
static GenOpFunc *gen_op_lwarx[] = {
&gen_op_lwarx_user,
&gen_op_lwarx_le_user,
/* lwarx */
GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
{
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
gen_addr_reg_index(ctx);
op_lwarx();
gen_op_store_T1_gpr(rD(ctx->opcode));
/* stwcx. */
GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
{
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
gen_addr_reg_index(ctx);
gen_op_load_gpr_T1(rS(ctx->opcode));
op_stwcx();
#define op_ldarx() (*gen_op_ldarx[ctx->mem_idx])()
#define op_stdcx() (*gen_op_stdcx[ctx->mem_idx])()
#if defined(CONFIG_USER_ONLY)
+/* User-mode only */
static GenOpFunc *gen_op_ldarx[] = {
&gen_op_ldarx_raw,
&gen_op_ldarx_le_raw,
&gen_op_stdcx_le_64_raw,
};
#else
+/* Full system */
static GenOpFunc *gen_op_ldarx[] = {
&gen_op_ldarx_user,
&gen_op_ldarx_le_user,
- &gen_op_ldarx_kernel,
- &gen_op_ldarx_le_kernel,
&gen_op_ldarx_64_user,
&gen_op_ldarx_le_64_user,
+ &gen_op_ldarx_kernel,
+ &gen_op_ldarx_le_kernel,
&gen_op_ldarx_64_kernel,
&gen_op_ldarx_le_64_kernel,
+#if defined(TARGET_PPC64H)
+ &gen_op_ldarx_hypv,
+ &gen_op_ldarx_le_hypv,
+ &gen_op_ldarx_64_hypv,
+ &gen_op_ldarx_le_64_hypv,
+#endif
};
static GenOpFunc *gen_op_stdcx[] = {
&gen_op_stdcx_user,
&gen_op_stdcx_le_user,
- &gen_op_stdcx_kernel,
- &gen_op_stdcx_le_kernel,
&gen_op_stdcx_64_user,
&gen_op_stdcx_le_64_user,
+ &gen_op_stdcx_kernel,
+ &gen_op_stdcx_le_kernel,
&gen_op_stdcx_64_kernel,
&gen_op_stdcx_le_64_kernel,
+#if defined(TARGET_PPC64H)
+ &gen_op_stdcx_hypv,
+ &gen_op_stdcx_le_hypv,
+ &gen_op_stdcx_64_hypv,
+ &gen_op_stdcx_le_64_hypv,
+#endif
};
#endif
/* ldarx */
-GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_RES)
+GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B)
{
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
gen_addr_reg_index(ctx);
op_ldarx();
gen_op_store_T1_gpr(rD(ctx->opcode));
}
/* stdcx. */
-GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_RES)
+GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_64B)
{
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
gen_addr_reg_index(ctx);
gen_op_load_gpr_T1(rS(ctx->opcode));
op_stdcx();
#endif /* defined(TARGET_PPC64) */
/* sync */
-GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM_SYNC)
+GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC)
+{
+}
+
+/* wait */
+GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT)
{
+ /* Stop translation, as the CPU is supposed to sleep from now */
+ gen_op_wait();
+ GEN_EXCP(ctx, EXCP_HLT, 1);
}
/*** Floating-point load ***/
-#define GEN_LDF(width, opc) \
-GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
+#define GEN_LDF(width, opc, type) \
+GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, type) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
gen_addr_imm_index(ctx, 0); \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
}
-#define GEN_LDUF(width, opc) \
-GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
+#define GEN_LDUF(width, opc, type) \
+GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
if (unlikely(rA(ctx->opcode) == 0)) { \
- RET_INVAL(ctx); \
+ GEN_EXCP_INVAL(ctx); \
return; \
} \
gen_addr_imm_index(ctx, 0); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
-#define GEN_LDUXF(width, opc) \
-GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
+#define GEN_LDUXF(width, opc, type) \
+GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, type) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
if (unlikely(rA(ctx->opcode) == 0)) { \
- RET_INVAL(ctx); \
+ GEN_EXCP_INVAL(ctx); \
return; \
} \
gen_addr_reg_index(ctx); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
-#define GEN_LDXF(width, opc2, opc3) \
-GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
+#define GEN_LDXF(width, opc2, opc3, type) \
+GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, type) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
gen_addr_reg_index(ctx); \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
}
-#define GEN_LDFS(width, op) \
+#define GEN_LDFS(width, op, type) \
OP_LD_TABLE(width); \
-GEN_LDF(width, op | 0x20); \
-GEN_LDUF(width, op | 0x21); \
-GEN_LDUXF(width, op | 0x01); \
-GEN_LDXF(width, 0x17, op | 0x00)
+GEN_LDF(width, op | 0x20, type); \
+GEN_LDUF(width, op | 0x21, type); \
+GEN_LDUXF(width, op | 0x01, type); \
+GEN_LDXF(width, 0x17, op | 0x00, type)
/* lfd lfdu lfdux lfdx */
-GEN_LDFS(fd, 0x12);
+GEN_LDFS(fd, 0x12, PPC_FLOAT);
/* lfs lfsu lfsux lfsx */
-GEN_LDFS(fs, 0x10);
+GEN_LDFS(fs, 0x10, PPC_FLOAT);
/*** Floating-point store ***/
-#define GEN_STF(width, opc) \
-GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
+#define GEN_STF(width, opc, type) \
+GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, type) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
gen_addr_imm_index(ctx, 0); \
op_ldst(st##width); \
}
-#define GEN_STUF(width, opc) \
-GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
+#define GEN_STUF(width, opc, type) \
+GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
if (unlikely(rA(ctx->opcode) == 0)) { \
- RET_INVAL(ctx); \
+ GEN_EXCP_INVAL(ctx); \
return; \
} \
gen_addr_imm_index(ctx, 0); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
-#define GEN_STUXF(width, opc) \
-GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
+#define GEN_STUXF(width, opc, type) \
+GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, type) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
if (unlikely(rA(ctx->opcode) == 0)) { \
- RET_INVAL(ctx); \
+ GEN_EXCP_INVAL(ctx); \
return; \
} \
gen_addr_reg_index(ctx); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
-#define GEN_STXF(width, opc2, opc3) \
-GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
+#define GEN_STXF(width, opc2, opc3, type) \
+GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, type) \
{ \
if (unlikely(!ctx->fpu_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ GEN_EXCP_NO_FP(ctx); \
return; \
} \
gen_addr_reg_index(ctx); \
op_ldst(st##width); \
}
-#define GEN_STFS(width, op) \
+#define GEN_STFS(width, op, type) \
OP_ST_TABLE(width); \
-GEN_STF(width, op | 0x20); \
-GEN_STUF(width, op | 0x21); \
-GEN_STUXF(width, op | 0x01); \
-GEN_STXF(width, 0x17, op | 0x00)
+GEN_STF(width, op | 0x20, type); \
+GEN_STUF(width, op | 0x21, type); \
+GEN_STUXF(width, op | 0x01, type); \
+GEN_STXF(width, 0x17, op | 0x00, type)
/* stfd stfdu stfdux stfdx */
-GEN_STFS(fd, 0x16);
+GEN_STFS(fd, 0x16, PPC_FLOAT);
/* stfs stfsu stfsux stfsx */
-GEN_STFS(fs, 0x14);
+GEN_STFS(fs, 0x14, PPC_FLOAT);
/* Optional: */
/* stfiwx */
-GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
-{
- if (unlikely(!ctx->fpu_enabled)) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
- return;
- }
- gen_addr_reg_index(ctx);
- /* XXX: TODO: memcpy low order 32 bits of FRP(rs) into memory */
- RET_INVAL(ctx);
-}
+OP_ST_TABLE(fiwx);
+GEN_STXF(fiwx, 0x17, 0x1E, PPC_FLOAT_STFIWX);
/*** Branch ***/
-
-static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+static always_inline void gen_goto_tb (DisasContext *ctx, int n,
+ target_ulong dest)
{
TranslationBlock *tb;
tb = ctx->tb;
}
}
+static always_inline void gen_setlr (DisasContext *ctx, target_ulong nip)
+{
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode != 0 && (nip >> 32))
+ gen_op_setlr_64(ctx->nip >> 32, ctx->nip);
+ else
+#endif
+ gen_op_setlr(ctx->nip);
+}
+
/* b ba bl bla */
GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
target = ctx->nip + li - 4;
else
target = li;
- if (LK(ctx->opcode)) {
#if defined(TARGET_PPC64)
- if (ctx->sf_mode)
- gen_op_setlr_64(ctx->nip >> 32, ctx->nip);
- else
+ if (!ctx->sf_mode)
+ target = (uint32_t)target;
#endif
- gen_op_setlr(ctx->nip);
- }
+ if (LK(ctx->opcode))
+ gen_setlr(ctx, ctx->nip);
gen_goto_tb(ctx, 0, target);
- ctx->exception = EXCP_BRANCH;
+ ctx->exception = POWERPC_EXCP_BRANCH;
}
#define BCOND_IM 0
#define BCOND_LR 1
#define BCOND_CTR 2
-static inline void gen_bcond(DisasContext *ctx, int type)
+static always_inline void gen_bcond (DisasContext *ctx, int type)
{
target_ulong target = 0;
target_ulong li;
} else {
target = li;
}
+#if defined(TARGET_PPC64)
+ if (!ctx->sf_mode)
+ target = (uint32_t)target;
+#endif
break;
case BCOND_CTR:
gen_op_movl_T1_ctr();
gen_op_movl_T1_lr();
break;
}
- if (LK(ctx->opcode)) {
-#if defined(TARGET_PPC64)
- if (ctx->sf_mode)
- gen_op_setlr_64(ctx->nip >> 32, ctx->nip);
- else
-#endif
- gen_op_setlr(ctx->nip);
- }
+ if (LK(ctx->opcode))
+ gen_setlr(ctx, ctx->nip);
if (bo & 0x10) {
/* No CR condition */
switch (bo & 0x6) {
case 6:
if (type == BCOND_IM) {
gen_goto_tb(ctx, 0, target);
+ goto out;
} else {
#if defined(TARGET_PPC64)
if (ctx->sf_mode)
#endif
gen_op_b_T1();
gen_op_reset_T0();
+ goto no_test;
}
- goto no_test;
+ break;
}
} else {
mask = 1 << (3 - (bi & 0x03));
else
#endif
gen_op_test_ctr_false(mask);
- break;
+ break;
case 2:
#if defined(TARGET_PPC64)
if (ctx->sf_mode)
#endif
gen_op_btest_T1(ctx->nip);
gen_op_reset_T0();
+ no_test:
+ if (ctx->singlestep_enabled)
+ gen_op_debug();
+ gen_op_exit_tb();
}
- no_test:
- if (ctx->singlestep_enabled)
- gen_op_debug();
- gen_op_exit_tb();
- ctx->exception = EXCP_BRANCH;
+ out:
+ ctx->exception = POWERPC_EXCP_BRANCH;
}
GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
-{
+{
gen_bcond(ctx, BCOND_IM);
}
GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW)
-{
+{
gen_bcond(ctx, BCOND_CTR);
}
GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
-{
+{
gen_bcond(ctx, BCOND_LR);
}
GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
/* Restore CPU state */
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_rfi();
- RET_CHG_FLOW(ctx);
+ GEN_SYNC(ctx);
#endif
}
#if defined(TARGET_PPC64)
-GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_FLOW)
+GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
/* Restore CPU state */
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_rfid();
- RET_CHG_FLOW(ctx);
+ GEN_SYNC(ctx);
#endif
}
#endif
-/* sc */
-GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
+#if defined(TARGET_PPC64H)
+GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64B)
{
#if defined(CONFIG_USER_ONLY)
- RET_EXCP(ctx, EXCP_SYSCALL_USER, 0);
+ GEN_EXCP_PRIVOPC(ctx);
#else
- RET_EXCP(ctx, EXCP_SYSCALL, 0);
+ /* Restore CPU state */
+ if (unlikely(ctx->supervisor <= 1)) {
+ GEN_EXCP_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_hrfid();
+ GEN_SYNC(ctx);
#endif
}
+#endif
+
+/* sc */
+#if defined(CONFIG_USER_ONLY)
+#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER
+#else
+#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL
+#endif
+GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW)
+{
+ uint32_t lev;
+
+ lev = (ctx->opcode >> 5) & 0x7F;
+ GEN_EXCP(ctx, POWERPC_SYSCALL, lev);
+}
/*** Trap ***/
/* tw */
GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC)
{
uint32_t crm, crn;
-
+
if (likely(ctx->opcode & 0x00100000)) {
crm = CRM(ctx->opcode);
if (likely((crm ^ (crm - 1)) == 0)) {
GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
return;
}
gen_op_load_msr();
#endif
/* mfspr */
-static inline void gen_op_mfspr (DisasContext *ctx)
+static always_inline void gen_op_mfspr (DisasContext *ctx)
{
void (*read_cb)(void *opaque, int sprn);
uint32_t sprn = SPR(ctx->opcode);
#if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64H)
+ if (ctx->supervisor == 2)
+ read_cb = ctx->spr_cb[sprn].hea_read;
+ else
+#endif
if (ctx->supervisor)
read_cb = ctx->spr_cb[sprn].oea_read;
else
gen_op_store_T0_gpr(rD(ctx->opcode));
} else {
/* Privilege exception */
- if (loglevel) {
- fprintf(logfile, "Trying to read priviledged spr %d %03x\n",
+ if (loglevel != 0) {
+ fprintf(logfile, "Trying to read privileged spr %d %03x\n",
sprn, sprn);
}
- printf("Trying to read priviledged spr %d %03x\n", sprn, sprn);
- RET_PRIVREG(ctx);
+ printf("Trying to read privileged spr %d %03x\n", sprn, sprn);
+ GEN_EXCP_PRIVREG(ctx);
}
} else {
/* Not defined */
- if (loglevel) {
+ if (loglevel != 0) {
fprintf(logfile, "Trying to read invalid spr %d %03x\n",
sprn, sprn);
}
printf("Trying to read invalid spr %d %03x\n", sprn, sprn);
- RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
+ GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR);
}
}
}
/* mftb */
-GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
+GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MFTB)
{
gen_op_mfspr(ctx);
}
GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
{
uint32_t crm, crn;
-
+
gen_op_load_gpr_T0(rS(ctx->opcode));
crm = CRM(ctx->opcode);
if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) {
/* mtmsr */
#if defined(TARGET_PPC64)
-GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_MISC)
+GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
return;
}
- gen_update_nip(ctx, ctx->nip);
gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_store_msr();
- /* Must stop the translation as machine state (may have) changed */
- RET_CHG_FLOW(ctx);
+ if (ctx->opcode & 0x00010000) {
+ /* Special form that does not need any synchronisation */
+ gen_op_update_riee();
+ } else {
+ /* XXX: we need to update nip before the store
+ * if we enter power saving mode, we will exit the loop
+ * directly from ppc_store_msr
+ */
+ gen_update_nip(ctx, ctx->nip);
+ gen_op_store_msr();
+ /* Must stop the translation as machine state (may have) changed */
+ /* Note that mtmsr is not always defined as context-synchronizing */
+ ctx->exception = POWERPC_EXCP_STOP;
+ }
#endif
}
#endif
GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
return;
}
- gen_update_nip(ctx, ctx->nip);
gen_op_load_gpr_T0(rS(ctx->opcode));
+ if (ctx->opcode & 0x00010000) {
+ /* Special form that does not need any synchronisation */
+ gen_op_update_riee();
+ } else {
+ /* XXX: we need to update nip before the store
+ * if we enter power saving mode, we will exit the loop
+ * directly from ppc_store_msr
+ */
+ gen_update_nip(ctx, ctx->nip);
#if defined(TARGET_PPC64)
- if (!ctx->sf_mode)
- gen_op_store_msr_32();
- else
+ if (!ctx->sf_mode)
+ gen_op_store_msr_32();
+ else
#endif
- gen_op_store_msr();
- /* Must stop the translation as machine state (may have) changed */
- RET_CHG_FLOW(ctx);
+ gen_op_store_msr();
+ /* Must stop the translation as machine state (may have) changed */
+ /* Note that mtmsrd is not always defined as context-synchronizing */
+ ctx->exception = POWERPC_EXCP_STOP;
+ }
#endif
}
uint32_t sprn = SPR(ctx->opcode);
#if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64H)
+ if (ctx->supervisor == 2)
+ write_cb = ctx->spr_cb[sprn].hea_write;
+ else
+#endif
if (ctx->supervisor)
write_cb = ctx->spr_cb[sprn].oea_write;
else
(*write_cb)(ctx, sprn);
} else {
/* Privilege exception */
- if (loglevel) {
- fprintf(logfile, "Trying to write priviledged spr %d %03x\n",
+ if (loglevel != 0) {
+ fprintf(logfile, "Trying to write privileged spr %d %03x\n",
sprn, sprn);
}
- printf("Trying to write priviledged spr %d %03x\n", sprn, sprn);
- RET_PRIVREG(ctx);
+ printf("Trying to write privileged spr %d %03x\n", sprn, sprn);
+ GEN_EXCP_PRIVREG(ctx);
}
} else {
/* Not defined */
- if (loglevel) {
+ if (loglevel != 0) {
fprintf(logfile, "Trying to write invalid spr %d %03x\n",
sprn, sprn);
}
printf("Trying to write invalid spr %d %03x\n", sprn, sprn);
- RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
+ GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR);
}
}
* We just have to flush tb while invalidating instruction cache lines...
*/
/* dcbf */
-GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE)
+GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE)
{
gen_addr_reg_index(ctx);
op_ldst(lbz);
GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_addr_reg_index(ctx);
}
/* dcbt */
-GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE)
+GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x02000001, PPC_CACHE)
{
+ /* interpreted as no-op */
/* XXX: specification say this is treated as a load by the MMU
* but does not generate any exception
*/
}
/* dcbtst */
-GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE)
+GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x02000001, PPC_CACHE)
{
+ /* interpreted as no-op */
/* XXX: specification say this is treated as a load by the MMU
* but does not generate any exception
*/
}
/* dcbz */
-#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
-#if defined(TARGET_PPC64)
+#define op_dcbz(n) (*gen_op_dcbz[n][ctx->mem_idx])()
#if defined(CONFIG_USER_ONLY)
-static GenOpFunc *gen_op_dcbz[] = {
- &gen_op_dcbz_raw,
- &gen_op_dcbz_raw,
- &gen_op_dcbz_64_raw,
- &gen_op_dcbz_64_raw,
-};
-#else
-static GenOpFunc *gen_op_dcbz[] = {
- &gen_op_dcbz_user,
- &gen_op_dcbz_user,
- &gen_op_dcbz_kernel,
- &gen_op_dcbz_kernel,
- &gen_op_dcbz_64_user,
- &gen_op_dcbz_64_user,
- &gen_op_dcbz_64_kernel,
- &gen_op_dcbz_64_kernel,
-};
+/* User-mode only */
+static GenOpFunc *gen_op_dcbz[4][4] = {
+ {
+ &gen_op_dcbz_l32_raw,
+ &gen_op_dcbz_l32_raw,
+#if defined(TARGET_PPC64)
+ &gen_op_dcbz_l32_64_raw,
+ &gen_op_dcbz_l32_64_raw,
+#endif
+ },
+ {
+ &gen_op_dcbz_l64_raw,
+ &gen_op_dcbz_l64_raw,
+#if defined(TARGET_PPC64)
+ &gen_op_dcbz_l64_64_raw,
+ &gen_op_dcbz_l64_64_raw,
+#endif
+ },
+ {
+ &gen_op_dcbz_l128_raw,
+ &gen_op_dcbz_l128_raw,
+#if defined(TARGET_PPC64)
+ &gen_op_dcbz_l128_64_raw,
+ &gen_op_dcbz_l128_64_raw,
+#endif
+ },
+ {
+ &gen_op_dcbz_raw,
+ &gen_op_dcbz_raw,
+#if defined(TARGET_PPC64)
+ &gen_op_dcbz_64_raw,
+ &gen_op_dcbz_64_raw,
#endif
+ },
+};
#else
-#if defined(CONFIG_USER_ONLY)
-static GenOpFunc *gen_op_dcbz[] = {
- &gen_op_dcbz_raw,
- &gen_op_dcbz_raw,
+#if defined(TARGET_PPC64)
+/* Full system - 64 bits mode */
+static GenOpFunc *gen_op_dcbz[4][12] = {
+ {
+ &gen_op_dcbz_l32_user,
+ &gen_op_dcbz_l32_user,
+ &gen_op_dcbz_l32_64_user,
+ &gen_op_dcbz_l32_64_user,
+ &gen_op_dcbz_l32_kernel,
+ &gen_op_dcbz_l32_kernel,
+ &gen_op_dcbz_l32_64_kernel,
+ &gen_op_dcbz_l32_64_kernel,
+#if defined(TARGET_PPC64H)
+ &gen_op_dcbz_l32_hypv,
+ &gen_op_dcbz_l32_hypv,
+ &gen_op_dcbz_l32_64_hypv,
+ &gen_op_dcbz_l32_64_hypv,
+#endif
+ },
+ {
+ &gen_op_dcbz_l64_user,
+ &gen_op_dcbz_l64_user,
+ &gen_op_dcbz_l64_64_user,
+ &gen_op_dcbz_l64_64_user,
+ &gen_op_dcbz_l64_kernel,
+ &gen_op_dcbz_l64_kernel,
+ &gen_op_dcbz_l64_64_kernel,
+ &gen_op_dcbz_l64_64_kernel,
+#if defined(TARGET_PPC64H)
+ &gen_op_dcbz_l64_hypv,
+ &gen_op_dcbz_l64_hypv,
+ &gen_op_dcbz_l64_64_hypv,
+ &gen_op_dcbz_l64_64_hypv,
+#endif
+ },
+ {
+ &gen_op_dcbz_l128_user,
+ &gen_op_dcbz_l128_user,
+ &gen_op_dcbz_l128_64_user,
+ &gen_op_dcbz_l128_64_user,
+ &gen_op_dcbz_l128_kernel,
+ &gen_op_dcbz_l128_kernel,
+ &gen_op_dcbz_l128_64_kernel,
+ &gen_op_dcbz_l128_64_kernel,
+#if defined(TARGET_PPC64H)
+ &gen_op_dcbz_l128_hypv,
+ &gen_op_dcbz_l128_hypv,
+ &gen_op_dcbz_l128_64_hypv,
+ &gen_op_dcbz_l128_64_hypv,
+#endif
+ },
+ {
+ &gen_op_dcbz_user,
+ &gen_op_dcbz_user,
+ &gen_op_dcbz_64_user,
+ &gen_op_dcbz_64_user,
+ &gen_op_dcbz_kernel,
+ &gen_op_dcbz_kernel,
+ &gen_op_dcbz_64_kernel,
+ &gen_op_dcbz_64_kernel,
+#if defined(TARGET_PPC64H)
+ &gen_op_dcbz_hypv,
+ &gen_op_dcbz_hypv,
+ &gen_op_dcbz_64_hypv,
+ &gen_op_dcbz_64_hypv,
+#endif
+ },
};
#else
-static GenOpFunc *gen_op_dcbz[] = {
- &gen_op_dcbz_user,
- &gen_op_dcbz_user,
- &gen_op_dcbz_kernel,
- &gen_op_dcbz_kernel,
+/* Full system - 32 bits mode */
+static GenOpFunc *gen_op_dcbz[4][4] = {
+ {
+ &gen_op_dcbz_l32_user,
+ &gen_op_dcbz_l32_user,
+ &gen_op_dcbz_l32_kernel,
+ &gen_op_dcbz_l32_kernel,
+ },
+ {
+ &gen_op_dcbz_l64_user,
+ &gen_op_dcbz_l64_user,
+ &gen_op_dcbz_l64_kernel,
+ &gen_op_dcbz_l64_kernel,
+ },
+ {
+ &gen_op_dcbz_l128_user,
+ &gen_op_dcbz_l128_user,
+ &gen_op_dcbz_l128_kernel,
+ &gen_op_dcbz_l128_kernel,
+ },
+ {
+ &gen_op_dcbz_user,
+ &gen_op_dcbz_user,
+ &gen_op_dcbz_kernel,
+ &gen_op_dcbz_kernel,
+ },
};
#endif
#endif
-GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE)
+static always_inline void handler_dcbz (DisasContext *ctx,
+ int dcache_line_size)
+{
+ int n;
+
+ switch (dcache_line_size) {
+ case 32:
+ n = 0;
+ break;
+ case 64:
+ n = 1;
+ break;
+ case 128:
+ n = 2;
+ break;
+ default:
+ n = 3;
+ break;
+ }
+ op_dcbz(n);
+}
+
+GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE_DCBZ)
{
gen_addr_reg_index(ctx);
- op_dcbz();
+ handler_dcbz(ctx, ctx->dcache_line_size);
+ gen_op_check_reservation();
+}
+
+GEN_HANDLER(dcbz_970, 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT)
+{
+ gen_addr_reg_index(ctx);
+ if (ctx->opcode & 0x00200000)
+ handler_dcbz(ctx, ctx->dcache_line_size);
+ else
+ handler_dcbz(ctx, -1);
gen_op_check_reservation();
}
/* icbi */
#define op_icbi() (*gen_op_icbi[ctx->mem_idx])()
-#if defined(TARGET_PPC64)
#if defined(CONFIG_USER_ONLY)
+/* User-mode only */
static GenOpFunc *gen_op_icbi[] = {
&gen_op_icbi_raw,
&gen_op_icbi_raw,
+#if defined(TARGET_PPC64)
&gen_op_icbi_64_raw,
&gen_op_icbi_64_raw,
+#endif
};
#else
+/* Full system - 64 bits mode */
+#if defined(TARGET_PPC64)
static GenOpFunc *gen_op_icbi[] = {
&gen_op_icbi_user,
&gen_op_icbi_user,
- &gen_op_icbi_kernel,
- &gen_op_icbi_kernel,
&gen_op_icbi_64_user,
&gen_op_icbi_64_user,
+ &gen_op_icbi_kernel,
+ &gen_op_icbi_kernel,
&gen_op_icbi_64_kernel,
&gen_op_icbi_64_kernel,
-};
+#if defined(TARGET_PPC64H)
+ &gen_op_icbi_hypv,
+ &gen_op_icbi_hypv,
+ &gen_op_icbi_64_hypv,
+ &gen_op_icbi_64_hypv,
#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-static GenOpFunc *gen_op_icbi[] = {
- &gen_op_icbi_raw,
- &gen_op_icbi_raw,
};
#else
+/* Full system - 32 bits mode */
static GenOpFunc *gen_op_icbi[] = {
&gen_op_icbi_user,
&gen_op_icbi_user,
};
#endif
#endif
+
GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE)
{
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
gen_addr_reg_index(ctx);
op_icbi();
- RET_STOP(ctx);
}
/* Optional: */
/* dcba */
-GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_OPT)
+GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA)
{
+ /* interpreted as no-op */
+ /* XXX: specification say this is treated as a store by the MMU
+ * but does not generate any exception
+ */
}
/*** Segment register manipulation ***/
GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
return;
}
gen_op_set_T1(SR(ctx->opcode));
GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
return;
}
gen_op_load_gpr_T1(rB(ctx->opcode));
GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
return;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_set_T1(SR(ctx->opcode));
gen_op_store_sr();
- RET_STOP(ctx);
#endif
}
GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
return;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_load_gpr_T1(rB(ctx->opcode));
gen_op_srli_T1(28);
gen_op_store_sr();
- RET_STOP(ctx);
#endif
}
+#if defined(TARGET_PPC64)
+/* Specific implementation for PowerPC 64 "bridge" emulation using SLB */
+/* mfsr */
+GEN_HANDLER(mfsr_64b, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVREG(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ GEN_EXCP_PRIVREG(ctx);
+ return;
+ }
+ gen_op_set_T1(SR(ctx->opcode));
+ gen_op_load_slb();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* mfsrin */
+GEN_HANDLER(mfsrin_64b, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT_64B)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVREG(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ GEN_EXCP_PRIVREG(ctx);
+ return;
+ }
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_srli_T1(28);
+ gen_op_load_slb();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* mtsr */
+GEN_HANDLER(mtsr_64b, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVREG(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ GEN_EXCP_PRIVREG(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_set_T1(SR(ctx->opcode));
+ gen_op_store_slb();
+#endif
+}
+
+/* mtsrin */
+GEN_HANDLER(mtsrin_64b, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT_64B)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVREG(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ GEN_EXCP_PRIVREG(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_srli_T1(28);
+ gen_op_store_slb();
+#endif
+}
+#endif /* defined(TARGET_PPC64) */
+
/*** Lookaside buffer management ***/
/* Optional & supervisor only: */
/* tlbia */
GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- if (loglevel)
+ if (loglevel != 0)
fprintf(logfile, "%s: ! supervisor\n", __func__);
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_tlbia();
- RET_STOP(ctx);
#endif
}
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_load_gpr_T0(rB(ctx->opcode));
else
#endif
gen_op_tlbie();
- RET_STOP(ctx);
#endif
}
GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
/* This has no effect: it should ensure that all previous
* tlbie have completed
*/
- RET_STOP(ctx);
+ GEN_STOP(ctx);
#endif
}
GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- if (loglevel)
+ if (loglevel != 0)
fprintf(logfile, "%s: ! supervisor\n", __func__);
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_slbia();
- RET_STOP(ctx);
#endif
}
GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_load_gpr_T0(rB(ctx->opcode));
gen_op_slbie();
- RET_STOP(ctx);
#endif
}
#endif
/* Optional: */
#define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
#define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])()
-#if defined(TARGET_PPC64)
#if defined(CONFIG_USER_ONLY)
+/* User-mode only */
static GenOpFunc *gen_op_eciwx[] = {
&gen_op_eciwx_raw,
&gen_op_eciwx_le_raw,
+#if defined(TARGET_PPC64)
&gen_op_eciwx_64_raw,
&gen_op_eciwx_le_64_raw,
+#endif
};
static GenOpFunc *gen_op_ecowx[] = {
&gen_op_ecowx_raw,
&gen_op_ecowx_le_raw,
+#if defined(TARGET_PPC64)
&gen_op_ecowx_64_raw,
&gen_op_ecowx_le_64_raw,
+#endif
};
#else
+#if defined(TARGET_PPC64)
+/* Full system - 64 bits mode */
static GenOpFunc *gen_op_eciwx[] = {
&gen_op_eciwx_user,
&gen_op_eciwx_le_user,
- &gen_op_eciwx_kernel,
- &gen_op_eciwx_le_kernel,
&gen_op_eciwx_64_user,
&gen_op_eciwx_le_64_user,
+ &gen_op_eciwx_kernel,
+ &gen_op_eciwx_le_kernel,
&gen_op_eciwx_64_kernel,
&gen_op_eciwx_le_64_kernel,
+#if defined(TARGET_PPC64H)
+ &gen_op_eciwx_hypv,
+ &gen_op_eciwx_le_hypv,
+ &gen_op_eciwx_64_hypv,
+ &gen_op_eciwx_le_64_hypv,
+#endif
};
static GenOpFunc *gen_op_ecowx[] = {
&gen_op_ecowx_user,
&gen_op_ecowx_le_user,
- &gen_op_ecowx_kernel,
- &gen_op_ecowx_le_kernel,
&gen_op_ecowx_64_user,
&gen_op_ecowx_le_64_user,
+ &gen_op_ecowx_kernel,
+ &gen_op_ecowx_le_kernel,
&gen_op_ecowx_64_kernel,
&gen_op_ecowx_le_64_kernel,
-};
+#if defined(TARGET_PPC64H)
+ &gen_op_ecowx_hypv,
+ &gen_op_ecowx_le_hypv,
+ &gen_op_ecowx_64_hypv,
+ &gen_op_ecowx_le_64_hypv,
#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-static GenOpFunc *gen_op_eciwx[] = {
- &gen_op_eciwx_raw,
- &gen_op_eciwx_le_raw,
-};
-static GenOpFunc *gen_op_ecowx[] = {
- &gen_op_ecowx_raw,
- &gen_op_ecowx_le_raw,
};
#else
+/* Full system - 32 bits mode */
static GenOpFunc *gen_op_eciwx[] = {
&gen_op_eciwx_user,
&gen_op_eciwx_le_user,
}
/* clcs */
-GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) /* 601 ? */
+GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_POWER_clcs();
}
/* As lscbx load from memory byte after byte, it's always endian safe */
-#define op_POWER_lscbx(start, ra, rb) \
+#define op_POWER_lscbx(start, ra, rb) \
(*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb)
#if defined(CONFIG_USER_ONLY)
static GenOpFunc3 *gen_op_POWER_lscbx[] = {
GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
{
/* XXX: TODO */
- RET_INVAL(ctx);
+ GEN_EXCP_INVAL(ctx);
}
/* esa */
GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
{
/* XXX: TODO */
- RET_INVAL(ctx);
+ GEN_EXCP_INVAL(ctx);
}
/* mfrom */
GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_load_gpr_T0(rA(ctx->opcode));
/* 602 - 603 - G2 TLB management */
/* tlbld */
-GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
+GEN_HANDLER(tlbld_6xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_load_gpr_T0(rB(ctx->opcode));
gen_op_6xx_tlbld();
- RET_STOP(ctx);
#endif
}
/* tlbli */
-GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
+GEN_HANDLER(tlbli_6xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_load_gpr_T0(rB(ctx->opcode));
gen_op_6xx_tlbli();
- RET_STOP(ctx);
+#endif
+}
+
+/* 74xx TLB management */
+/* tlbld */
+GEN_HANDLER(tlbld_74xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ GEN_EXCP_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rB(ctx->opcode));
+ gen_op_74xx_tlbld();
+#endif
+}
+
+/* tlbli */
+GEN_HANDLER(tlbli_74xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ GEN_EXCP_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rB(ctx->opcode));
+ gen_op_74xx_tlbli();
#endif
}
/* cli */
GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER)
{
- /* Cache line invalidate: priviledged and treated as no-op */
+ /* Cache line invalidate: privileged and treated as no-op */
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
#endif
GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
int ra = rA(ctx->opcode);
GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_addr_reg_index(ctx);
GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_POWER_rfsvc();
- RET_CHG_FLOW(ctx);
+ GEN_SYNC(ctx);
#endif
}
}
/* BookE specific instructions */
-GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE)
+/* XXX: not implemented on 440 ? */
+GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE_EXT)
{
/* XXX: TODO */
- RET_INVAL(ctx);
+ GEN_EXCP_INVAL(ctx);
}
-GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE)
+/* XXX: not implemented on 440 ? */
+GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE_EXT)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_addr_reg_index(ctx);
else
#endif
gen_op_tlbie();
- RET_STOP(ctx);
#endif
}
/* All 405 MAC instructions are translated here */
-static inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3,
- int ra, int rb, int rt, int Rc)
+static always_inline void gen_405_mulladd_insn (DisasContext *ctx,
+ int opc2, int opc3,
+ int ra, int rb, int rt, int Rc)
{
gen_op_load_gpr_T0(ra);
gen_op_load_gpr_T1(rb);
GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
#else
uint32_t dcrn = SPR(ctx->opcode);
if (unlikely(!ctx->supervisor)) {
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
return;
}
gen_op_set_T0(dcrn);
GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
#else
uint32_t dcrn = SPR(ctx->opcode);
if (unlikely(!ctx->supervisor)) {
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
return;
}
gen_op_set_T0(dcrn);
}
/* mfdcrx */
-GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000001, PPC_BOOKE)
+/* XXX: not implemented on 440 ? */
+GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_BOOKE_EXT)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
return;
}
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_load_dcr();
gen_op_store_T0_gpr(rD(ctx->opcode));
+ /* Note: Rc update flag set leads to undefined state of Rc0 */
#endif
}
/* mtdcrx */
-GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000001, PPC_BOOKE)
+/* XXX: not implemented on 440 ? */
+GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_BOOKE_EXT)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVREG(ctx);
+ GEN_EXCP_PRIVREG(ctx);
return;
}
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_load_gpr_T1(rS(ctx->opcode));
gen_op_store_dcr();
+ /* Note: Rc update flag set leads to undefined state of Rc0 */
#endif
}
+/* mfdcrux (PPC 460) : user-mode access to DCR */
+GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x00000000, PPC_DCRUX)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_dcr();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ /* Note: Rc update flag set leads to undefined state of Rc0 */
+}
+
+/* mtdcrux (PPC 460) : user-mode access to DCR */
+GEN_HANDLER(mtdcrux, 0x1F, 0x03, 0x0D, 0x00000000, PPC_DCRUX)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ gen_op_store_dcr();
+ /* Note: Rc update flag set leads to undefined state of Rc0 */
+}
+
/* dccci */
GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
/* interpreted as no-op */
GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_addr_reg_index(ctx);
}
/* icbt */
-GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_SPEC)
+GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT)
{
/* interpreted as no-op */
/* XXX: specification say this is treated as a load by the MMU
GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
/* interpreted as no-op */
GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
/* interpreted as no-op */
GEN_HANDLER(rfci_40x, 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
/* Restore CPU state */
gen_op_40x_rfci();
- RET_CHG_FLOW(ctx);
+ GEN_SYNC(ctx);
#endif
}
GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
/* Restore CPU state */
gen_op_rfci();
- RET_CHG_FLOW(ctx);
+ GEN_SYNC(ctx);
#endif
}
/* BookE specific */
-GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE)
+/* XXX: not implemented on 440 ? */
+GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE_EXT)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
/* Restore CPU state */
gen_op_rfdi();
- RET_CHG_FLOW(ctx);
+ GEN_SYNC(ctx);
#endif
}
-GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_BOOKE)
+/* XXX: not implemented on 440 ? */
+GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
/* Restore CPU state */
gen_op_rfmci();
- RET_CHG_FLOW(ctx);
+ GEN_SYNC(ctx);
#endif
}
+
/* TLB management - PowerPC 405 implementation */
/* tlbre */
-GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC)
+GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
switch (rB(ctx->opcode)) {
gen_op_store_T0_gpr(rD(ctx->opcode));
break;
default:
- RET_INVAL(ctx);
+ GEN_EXCP_INVAL(ctx);
break;
}
#endif
}
/* tlbsx - tlbsx. */
-GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC)
+GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_addr_reg_index(ctx);
+ gen_op_4xx_tlbsx();
if (Rc(ctx->opcode))
- gen_op_4xx_tlbsx_();
- else
- gen_op_4xx_tlbsx();
+ gen_op_4xx_tlbsx_check();
gen_op_store_T0_gpr(rD(ctx->opcode));
#endif
}
/* tlbwe */
-GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC)
+GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
switch (rB(ctx->opcode)) {
gen_op_4xx_tlbwe_lo();
break;
default:
- RET_INVAL(ctx);
+ GEN_EXCP_INVAL(ctx);
+ break;
+ }
+#endif
+}
+
+/* TLB management - PowerPC 440 implementation */
+/* tlbre */
+GEN_HANDLER(tlbre_440, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ GEN_EXCP_PRIVOPC(ctx);
+ return;
+ }
+ switch (rB(ctx->opcode)) {
+ case 0:
+ case 1:
+ case 2:
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_440_tlbre(rB(ctx->opcode));
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ break;
+ default:
+ GEN_EXCP_INVAL(ctx);
+ break;
+ }
+#endif
+}
+
+/* tlbsx - tlbsx. */
+GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ GEN_EXCP_PRIVOPC(ctx);
+ return;
+ }
+ gen_addr_reg_index(ctx);
+ gen_op_440_tlbsx();
+ if (Rc(ctx->opcode))
+ gen_op_4xx_tlbsx_check();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* tlbwe */
+GEN_HANDLER(tlbwe_440, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ GEN_EXCP_PRIVOPC(ctx);
+ return;
+ }
+ switch (rB(ctx->opcode)) {
+ case 0:
+ case 1:
+ case 2:
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ gen_op_440_tlbwe(rB(ctx->opcode));
+ break;
+ default:
+ GEN_EXCP_INVAL(ctx);
break;
}
#endif
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_load_gpr_T0(rD(ctx->opcode));
gen_op_wrte();
- RET_EXCP(ctx, EXCP_MTMSR, 0);
+ /* Stop translation to have a chance to raise an exception
+ * if we just set msr_ee to 1
+ */
+ GEN_STOP(ctx);
#endif
}
GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON)
{
#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
- RET_PRIVOPC(ctx);
+ GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_set_T0(ctx->opcode & 0x00010000);
gen_op_wrte();
- RET_EXCP(ctx, EXCP_MTMSR, 0);
+ /* Stop translation to have a chance to raise an exception
+ * if we just set msr_ee to 1
+ */
+ GEN_STOP(ctx);
#endif
}
-/* PPC 440 specific instructions */
+/* PowerPC 440 specific instructions */
/* dlmzb */
GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
{
}
/* msync replaces sync on 440 */
-GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_BOOKE)
+GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE)
{
/* interpreted as no-op */
}
*/
}
-#if defined(TARGET_PPCSPE)
+/*** Altivec vector extension ***/
+/* Altivec registers moves */
+GEN32(gen_op_load_avr_A0, gen_op_load_avr_A0_avr);
+GEN32(gen_op_load_avr_A1, gen_op_load_avr_A1_avr);
+GEN32(gen_op_load_avr_A2, gen_op_load_avr_A2_avr);
+
+GEN32(gen_op_store_A0_avr, gen_op_store_A0_avr_avr);
+GEN32(gen_op_store_A1_avr, gen_op_store_A1_avr_avr);
+#if 0 // unused
+GEN32(gen_op_store_A2_avr, gen_op_store_A2_avr_avr);
+#endif
+
+#define op_vr_ldst(name) (*gen_op_##name[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
+/* User-mode only - 64 bits mode */
+#define OP_VR_LD_TABLE(name) \
+static GenOpFunc *gen_op_vr_l##name[] = { \
+ &gen_op_vr_l##name##_raw, \
+ &gen_op_vr_l##name##_le_raw, \
+ &gen_op_vr_l##name##_64_raw, \
+ &gen_op_vr_l##name##_le_64_raw, \
+};
+#define OP_VR_ST_TABLE(name) \
+static GenOpFunc *gen_op_vr_st##name[] = { \
+ &gen_op_vr_st##name##_raw, \
+ &gen_op_vr_st##name##_le_raw, \
+ &gen_op_vr_st##name##_64_raw, \
+ &gen_op_vr_st##name##_le_64_raw, \
+};
+#else /* defined(TARGET_PPC64) */
+/* User-mode only - 32 bits mode */
+#define OP_VR_LD_TABLE(name) \
+static GenOpFunc *gen_op_vr_l##name[] = { \
+ &gen_op_vr_l##name##_raw, \
+ &gen_op_vr_l##name##_le_raw, \
+};
+#define OP_VR_ST_TABLE(name) \
+static GenOpFunc *gen_op_vr_st##name[] = { \
+ &gen_op_vr_st##name##_raw, \
+ &gen_op_vr_st##name##_le_raw, \
+};
+#endif /* defined(TARGET_PPC64) */
+#else /* defined(CONFIG_USER_ONLY) */
+#if defined(TARGET_PPC64H)
+/* Full system with hypervisor mode */
+#define OP_VR_LD_TABLE(name) \
+static GenOpFunc *gen_op_vr_l##name[] = { \
+ &gen_op_vr_l##name##_user, \
+ &gen_op_vr_l##name##_le_user, \
+ &gen_op_vr_l##name##_64_user, \
+ &gen_op_vr_l##name##_le_64_user, \
+ &gen_op_vr_l##name##_kernel, \
+ &gen_op_vr_l##name##_le_kernel, \
+ &gen_op_vr_l##name##_64_kernel, \
+ &gen_op_vr_l##name##_le_64_kernel, \
+ &gen_op_vr_l##name##_hypv, \
+ &gen_op_vr_l##name##_le_hypv, \
+ &gen_op_vr_l##name##_64_hypv, \
+ &gen_op_vr_l##name##_le_64_hypv, \
+};
+#define OP_VR_ST_TABLE(name) \
+static GenOpFunc *gen_op_vr_st##name[] = { \
+ &gen_op_vr_st##name##_user, \
+ &gen_op_vr_st##name##_le_user, \
+ &gen_op_vr_st##name##_64_user, \
+ &gen_op_vr_st##name##_le_64_user, \
+ &gen_op_vr_st##name##_kernel, \
+ &gen_op_vr_st##name##_le_kernel, \
+ &gen_op_vr_st##name##_64_kernel, \
+ &gen_op_vr_st##name##_le_64_kernel, \
+ &gen_op_vr_st##name##_hypv, \
+ &gen_op_vr_st##name##_le_hypv, \
+ &gen_op_vr_st##name##_64_hypv, \
+ &gen_op_vr_st##name##_le_64_hypv, \
+};
+#elif defined(TARGET_PPC64)
+/* Full system - 64 bits mode */
+#define OP_VR_LD_TABLE(name) \
+static GenOpFunc *gen_op_vr_l##name[] = { \
+ &gen_op_vr_l##name##_user, \
+ &gen_op_vr_l##name##_le_user, \
+ &gen_op_vr_l##name##_64_user, \
+ &gen_op_vr_l##name##_le_64_user, \
+ &gen_op_vr_l##name##_kernel, \
+ &gen_op_vr_l##name##_le_kernel, \
+ &gen_op_vr_l##name##_64_kernel, \
+ &gen_op_vr_l##name##_le_64_kernel, \
+};
+#define OP_VR_ST_TABLE(name) \
+static GenOpFunc *gen_op_vr_st##name[] = { \
+ &gen_op_vr_st##name##_user, \
+ &gen_op_vr_st##name##_le_user, \
+ &gen_op_vr_st##name##_64_user, \
+ &gen_op_vr_st##name##_le_64_user, \
+ &gen_op_vr_st##name##_kernel, \
+ &gen_op_vr_st##name##_le_kernel, \
+ &gen_op_vr_st##name##_64_kernel, \
+ &gen_op_vr_st##name##_le_64_kernel, \
+};
+#else /* defined(TARGET_PPC64) */
+/* Full system - 32 bits mode */
+#define OP_VR_LD_TABLE(name) \
+static GenOpFunc *gen_op_vr_l##name[] = { \
+ &gen_op_vr_l##name##_user, \
+ &gen_op_vr_l##name##_le_user, \
+ &gen_op_vr_l##name##_kernel, \
+ &gen_op_vr_l##name##_le_kernel, \
+};
+#define OP_VR_ST_TABLE(name) \
+static GenOpFunc *gen_op_vr_st##name[] = { \
+ &gen_op_vr_st##name##_user, \
+ &gen_op_vr_st##name##_le_user, \
+ &gen_op_vr_st##name##_kernel, \
+ &gen_op_vr_st##name##_le_kernel, \
+};
+#endif /* defined(TARGET_PPC64) */
+#endif /* defined(CONFIG_USER_ONLY) */
+
+#define GEN_VR_LDX(name, opc2, opc3) \
+GEN_HANDLER(l##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) \
+{ \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ GEN_EXCP_NO_VR(ctx); \
+ return; \
+ } \
+ gen_addr_reg_index(ctx); \
+ op_vr_ldst(vr_l##name); \
+ gen_op_store_A0_avr(rD(ctx->opcode)); \
+}
+
+#define GEN_VR_STX(name, opc2, opc3) \
+GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) \
+{ \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ GEN_EXCP_NO_VR(ctx); \
+ return; \
+ } \
+ gen_addr_reg_index(ctx); \
+ gen_op_load_avr_A0(rS(ctx->opcode)); \
+ op_vr_ldst(vr_st##name); \
+}
+
+OP_VR_LD_TABLE(vx);
+GEN_VR_LDX(vx, 0x07, 0x03);
+/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */
+#define gen_op_vr_lvxl gen_op_vr_lvx
+GEN_VR_LDX(vxl, 0x07, 0x0B);
+
+OP_VR_ST_TABLE(vx);
+GEN_VR_STX(vx, 0x07, 0x07);
+/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
+#define gen_op_vr_stvxl gen_op_vr_stvx
+GEN_VR_STX(vxl, 0x07, 0x0F);
+
+#if defined(TARGET_PPCEMB)
/*** SPE extension ***/
/* Register moves */
}
/* Handler for undefined SPE opcodes */
-static inline void gen_speundef (DisasContext *ctx)
+static always_inline void gen_speundef (DisasContext *ctx)
{
- RET_INVAL(ctx);
+ GEN_EXCP_INVAL(ctx);
}
/* SPE load and stores */
-static inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh)
+static always_inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh)
{
target_long simm = rB(ctx->opcode);
#define op_spe_ldst(name) (*gen_op_##name[ctx->mem_idx])()
#if defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
+/* User-mode only - 64 bits mode */
#define OP_SPE_LD_TABLE(name) \
static GenOpFunc *gen_op_spe_l##name[] = { \
&gen_op_spe_l##name##_raw, \
&gen_op_spe_st##name##_le_64_raw, \
};
#else /* defined(TARGET_PPC64) */
+/* User-mode only - 32 bits mode */
#define OP_SPE_LD_TABLE(name) \
static GenOpFunc *gen_op_spe_l##name[] = { \
&gen_op_spe_l##name##_raw, \
};
#endif /* defined(TARGET_PPC64) */
#else /* defined(CONFIG_USER_ONLY) */
-#if defined(TARGET_PPC64)
+#if defined(TARGET_PPC64H)
+/* Full system with hypervisor mode */
#define OP_SPE_LD_TABLE(name) \
static GenOpFunc *gen_op_spe_l##name[] = { \
&gen_op_spe_l##name##_user, \
&gen_op_spe_l##name##_le_user, \
- &gen_op_spe_l##name##_kernel, \
- &gen_op_spe_l##name##_le_kernel, \
&gen_op_spe_l##name##_64_user, \
&gen_op_spe_l##name##_le_64_user, \
+ &gen_op_spe_l##name##_kernel, \
+ &gen_op_spe_l##name##_le_kernel, \
&gen_op_spe_l##name##_64_kernel, \
&gen_op_spe_l##name##_le_64_kernel, \
+ &gen_op_spe_l##name##_hypv, \
+ &gen_op_spe_l##name##_le_hypv, \
+ &gen_op_spe_l##name##_64_hypv, \
+ &gen_op_spe_l##name##_le_64_hypv, \
};
#define OP_SPE_ST_TABLE(name) \
static GenOpFunc *gen_op_spe_st##name[] = { \
&gen_op_spe_st##name##_user, \
&gen_op_spe_st##name##_le_user, \
+ &gen_op_spe_st##name##_64_user, \
+ &gen_op_spe_st##name##_le_64_user, \
&gen_op_spe_st##name##_kernel, \
&gen_op_spe_st##name##_le_kernel, \
+ &gen_op_spe_st##name##_64_kernel, \
+ &gen_op_spe_st##name##_le_64_kernel, \
+ &gen_op_spe_st##name##_hypv, \
+ &gen_op_spe_st##name##_le_hypv, \
+ &gen_op_spe_st##name##_64_hypv, \
+ &gen_op_spe_st##name##_le_64_hypv, \
+};
+#elif defined(TARGET_PPC64)
+/* Full system - 64 bits mode */
+#define OP_SPE_LD_TABLE(name) \
+static GenOpFunc *gen_op_spe_l##name[] = { \
+ &gen_op_spe_l##name##_user, \
+ &gen_op_spe_l##name##_le_user, \
+ &gen_op_spe_l##name##_64_user, \
+ &gen_op_spe_l##name##_le_64_user, \
+ &gen_op_spe_l##name##_kernel, \
+ &gen_op_spe_l##name##_le_kernel, \
+ &gen_op_spe_l##name##_64_kernel, \
+ &gen_op_spe_l##name##_le_64_kernel, \
+};
+#define OP_SPE_ST_TABLE(name) \
+static GenOpFunc *gen_op_spe_st##name[] = { \
+ &gen_op_spe_st##name##_user, \
+ &gen_op_spe_st##name##_le_user, \
&gen_op_spe_st##name##_64_user, \
&gen_op_spe_st##name##_le_64_user, \
+ &gen_op_spe_st##name##_kernel, \
+ &gen_op_spe_st##name##_le_kernel, \
&gen_op_spe_st##name##_64_kernel, \
&gen_op_spe_st##name##_le_64_kernel, \
};
#else /* defined(TARGET_PPC64) */
+/* Full system - 32 bits mode */
#define OP_SPE_LD_TABLE(name) \
static GenOpFunc *gen_op_spe_l##name[] = { \
&gen_op_spe_l##name##_user, \
#endif /* defined(CONFIG_USER_ONLY) */
#define GEN_SPE_LD(name, sh) \
-static inline void gen_evl##name (DisasContext *ctx) \
+static always_inline void gen_evl##name (DisasContext *ctx) \
{ \
if (unlikely(!ctx->spe_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ GEN_EXCP_NO_AP(ctx); \
return; \
} \
gen_addr_spe_imm_index(ctx, sh); \
}
#define GEN_SPE_LDX(name) \
-static inline void gen_evl##name##x (DisasContext *ctx) \
+static always_inline void gen_evl##name##x (DisasContext *ctx) \
{ \
if (unlikely(!ctx->spe_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ GEN_EXCP_NO_AP(ctx); \
return; \
} \
gen_addr_reg_index(ctx); \
GEN_SPE_LDX(name)
#define GEN_SPE_ST(name, sh) \
-static inline void gen_evst##name (DisasContext *ctx) \
+static always_inline void gen_evst##name (DisasContext *ctx) \
{ \
if (unlikely(!ctx->spe_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ GEN_EXCP_NO_AP(ctx); \
return; \
} \
gen_addr_spe_imm_index(ctx, sh); \
}
#define GEN_SPE_STX(name) \
-static inline void gen_evst##name##x (DisasContext *ctx) \
+static always_inline void gen_evst##name##x (DisasContext *ctx) \
{ \
if (unlikely(!ctx->spe_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ GEN_EXCP_NO_AP(ctx); \
return; \
} \
gen_addr_reg_index(ctx); \
/* SPE arithmetic and logic */
#define GEN_SPEOP_ARITH2(name) \
-static inline void gen_##name (DisasContext *ctx) \
+static always_inline void gen_##name (DisasContext *ctx) \
{ \
if (unlikely(!ctx->spe_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ GEN_EXCP_NO_AP(ctx); \
return; \
} \
gen_op_load_gpr64_T0(rA(ctx->opcode)); \
}
#define GEN_SPEOP_ARITH1(name) \
-static inline void gen_##name (DisasContext *ctx) \
+static always_inline void gen_##name (DisasContext *ctx) \
{ \
if (unlikely(!ctx->spe_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ GEN_EXCP_NO_AP(ctx); \
return; \
} \
gen_op_load_gpr64_T0(rA(ctx->opcode)); \
}
#define GEN_SPEOP_COMP(name) \
-static inline void gen_##name (DisasContext *ctx) \
+static always_inline void gen_##name (DisasContext *ctx) \
{ \
if (unlikely(!ctx->spe_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ GEN_EXCP_NO_AP(ctx); \
return; \
} \
gen_op_load_gpr64_T0(rA(ctx->opcode)); \
GEN_SPEOP_ARITH1(evrndw);
GEN_SPEOP_ARITH1(evcntlzw);
GEN_SPEOP_ARITH1(evcntlsw);
-static inline void gen_brinc (DisasContext *ctx)
+static always_inline void gen_brinc (DisasContext *ctx)
{
/* Note: brinc is usable even if SPE is disabled */
gen_op_load_gpr64_T0(rA(ctx->opcode));
}
#define GEN_SPEOP_ARITH_IMM2(name) \
-static inline void gen_##name##i (DisasContext *ctx) \
+static always_inline void gen_##name##i (DisasContext *ctx) \
{ \
if (unlikely(!ctx->spe_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ GEN_EXCP_NO_AP(ctx); \
return; \
} \
gen_op_load_gpr64_T0(rB(ctx->opcode)); \
}
#define GEN_SPEOP_LOGIC_IMM2(name) \
-static inline void gen_##name##i (DisasContext *ctx) \
+static always_inline void gen_##name##i (DisasContext *ctx) \
{ \
if (unlikely(!ctx->spe_enabled)) { \
- RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ GEN_EXCP_NO_AP(ctx); \
return; \
} \
gen_op_load_gpr64_T0(rA(ctx->opcode)); \
#define gen_evsrwiu gen_evsrwui
GEN_SPEOP_LOGIC_IMM2(evrlw);
-static inline void gen_evsplati (DisasContext *ctx)
+static always_inline void gen_evsplati (DisasContext *ctx)
{
int32_t imm = (int32_t)(rA(ctx->opcode) << 27) >> 27;
gen_op_store_T0_gpr64(rD(ctx->opcode));
}
-static inline void gen_evsplatfi (DisasContext *ctx)
+static always_inline void gen_evsplatfi (DisasContext *ctx)
{
uint32_t imm = rA(ctx->opcode) << 27;
GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, PPC_SPE); ////
GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, PPC_SPE); ////
-static inline void gen_evsel (DisasContext *ctx)
+static always_inline void gen_evsel (DisasContext *ctx)
{
if (unlikely(!ctx->spe_enabled)) {
- RET_EXCP(ctx, EXCP_NO_SPE, 0);
+ GEN_EXCP_NO_AP(ctx);
return;
}
gen_op_load_crf_T0(ctx->opcode & 0x7);
#endif
#endif
#define _GEN_OP_SPE_STWWE(suffix) \
-static inline void gen_op_spe_stwwe_##suffix (void) \
+static always_inline void gen_op_spe_stwwe_##suffix (void) \
{ \
gen_op_srli32_T1_64(); \
gen_op_spe_stwwo_##suffix(); \
}
#define _GEN_OP_SPE_STWWE_LE(suffix) \
-static inline void gen_op_spe_stwwe_le_##suffix (void) \
+static always_inline void gen_op_spe_stwwe_le_##suffix (void) \
{ \
gen_op_srli32_T1_64(); \
gen_op_spe_stwwo_le_##suffix(); \
#define GEN_OP_SPE_STWWE(suffix) \
_GEN_OP_SPE_STWWE(suffix); \
_GEN_OP_SPE_STWWE_LE(suffix); \
-static inline void gen_op_spe_stwwe_64_##suffix (void) \
+static always_inline void gen_op_spe_stwwe_64_##suffix (void) \
{ \
gen_op_srli32_T1_64(); \
gen_op_spe_stwwo_64_##suffix(); \
} \
-static inline void gen_op_spe_stwwe_le_64_##suffix (void) \
+static always_inline void gen_op_spe_stwwe_le_64_##suffix (void) \
{ \
gen_op_srli32_T1_64(); \
gen_op_spe_stwwo_le_64_##suffix(); \
GEN_SPEOP_ST(wwo, 2);
#define GEN_SPE_LDSPLAT(name, op, suffix) \
-static inline void gen_op_spe_l##name##_##suffix (void) \
+static always_inline void gen_op_spe_l##name##_##suffix (void) \
{ \
gen_op_##op##_##suffix(); \
gen_op_splatw_T1_64(); \
}
#define GEN_OP_SPE_LHE(suffix) \
-static inline void gen_op_spe_lhe_##suffix (void) \
+static always_inline void gen_op_spe_lhe_##suffix (void) \
{ \
gen_op_spe_lh_##suffix(); \
gen_op_sli16_T1_64(); \
}
#define GEN_OP_SPE_LHX(suffix) \
-static inline void gen_op_spe_lhx_##suffix (void) \
+static always_inline void gen_op_spe_lhx_##suffix (void) \
{ \
gen_op_spe_lh_##suffix(); \
gen_op_extsh_T1_64(); \
/*** SPE floating-point extension ***/
#define GEN_SPEFPUOP_CONV(name) \
-static inline void gen_##name (DisasContext *ctx) \
+static always_inline void gen_##name (DisasContext *ctx) \
{ \
gen_op_load_gpr64_T0(rB(ctx->opcode)); \
gen_op_##name(); \
/*****************************************************************************/
/* Misc PowerPC helpers */
-static inline uint32_t load_xer (CPUState *env)
+static always_inline uint32_t load_xer (CPUState *env)
{
return (xer_so << XER_SO) |
(xer_ov << XER_OV) |
(xer_cmp << XER_CMP);
}
-void cpu_dump_state(CPUState *env, FILE *f,
- int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
- int flags)
+void cpu_dump_state (CPUState *env, FILE *f,
+ int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ int flags)
{
#if defined(TARGET_PPC64) || 1
#define FILL ""
for (i = 0; i < 32; i++) {
if ((i & (RGPL - 1)) == 0)
cpu_fprintf(f, "GPR%02d", i);
- cpu_fprintf(f, " " REGX, env->gpr[i]);
+ cpu_fprintf(f, " " REGX, (target_ulong)env->gpr[i]);
if ((i & (RGPL - 1)) == (RGPL - 1))
cpu_fprintf(f, "\n");
}
if ((i & (RFPL - 1)) == (RFPL - 1))
cpu_fprintf(f, "\n");
}
+#if !defined(CONFIG_USER_ONLY)
cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX " " FILL FILL FILL
"SDR1 " REGX "\n",
env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
+#endif
#undef RGPL
#undef RFPL
}
/*****************************************************************************/
-static inline int gen_intermediate_code_internal (CPUState *env,
- TranslationBlock *tb,
- int search_pc)
+static always_inline int gen_intermediate_code_internal (CPUState *env,
+ TranslationBlock *tb,
+ int search_pc)
{
DisasContext ctx, *ctxp = &ctx;
opc_handler_t **table, *handler;
target_ulong pc_start;
uint16_t *gen_opc_end;
+ int supervisor;
+ int single_step, branch_step;
int j, lj = -1;
pc_start = tb->pc;
nb_gen_labels = 0;
ctx.nip = pc_start;
ctx.tb = tb;
- ctx.exception = EXCP_NONE;
+ ctx.exception = POWERPC_EXCP_NONE;
ctx.spr_cb = env->spr_cb;
-#if defined(CONFIG_USER_ONLY)
- ctx.mem_idx = msr_le;
-#if defined(TARGET_PPC64)
- ctx.mem_idx |= msr_sf << 1;
-#endif
-#else
- ctx.supervisor = 1 - msr_pr;
- ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le;
-#if defined(TARGET_PPC64)
- ctx.mem_idx |= msr_sf << 2;
-#endif
+ supervisor = env->mmu_idx;
+#if !defined(CONFIG_USER_ONLY)
+ ctx.supervisor = supervisor;
#endif
#if defined(TARGET_PPC64)
ctx.sf_mode = msr_sf;
+ ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | msr_le;
+#else
+ ctx.mem_idx = (supervisor << 1) | msr_le;
#endif
+ ctx.dcache_line_size = env->dcache_line_size;
ctx.fpu_enabled = msr_fp;
-#if defined(TARGET_PPCSPE)
- ctx.spe_enabled = msr_spe;
+#if defined(TARGET_PPCEMB)
+ if ((env->flags & POWERPC_FLAG_SPE) && msr_spe)
+ ctx.spe_enabled = msr_spe;
+ else
+ ctx.spe_enabled = 0;
#endif
- ctx.singlestep_enabled = env->singlestep_enabled;
+ if ((env->flags & POWERPC_FLAG_VRE) && msr_vr)
+ ctx.altivec_enabled = msr_vr;
+ else
+ ctx.altivec_enabled = 0;
+ if ((env->flags & POWERPC_FLAG_SE) && msr_se)
+ single_step = 1;
+ else
+ single_step = 0;
+ if ((env->flags & POWERPC_FLAG_BE) && msr_be)
+ branch_step = 1;
+ else
+ branch_step = 0;
+ ctx.singlestep_enabled = env->singlestep_enabled || single_step == 1;
#if defined (DO_SINGLE_STEP) && 0
/* Single step trace mode */
msr_se = 1;
#endif
/* Set env in case of segfault during code fetch */
- while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) {
+ while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) {
if (unlikely(env->nb_breakpoints > 0)) {
for (j = 0; j < env->nb_breakpoints; j++) {
if (env->breakpoints[j] == ctx.nip) {
- gen_update_nip(&ctx, ctx.nip);
+ gen_update_nip(&ctx, ctx.nip);
gen_op_debug();
break;
}
}
/* Is opcode *REALLY* valid ? */
if (unlikely(handler->handler == &gen_invalid)) {
- if (loglevel > 0) {
+ if (loglevel != 0) {
fprintf(logfile, "invalid/unsupported opcode: "
"%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n",
opc1(ctx.opcode), opc2(ctx.opcode),
}
} else {
if (unlikely((ctx.opcode & handler->inval) != 0)) {
- if (loglevel > 0) {
+ if (loglevel != 0) {
fprintf(logfile, "invalid bits: %08x for opcode: "
- "%02x -%02x - %02x (%08x) 0x" ADDRX "\n",
+ "%02x - %02x - %02x (%08x) 0x" ADDRX "\n",
ctx.opcode & handler->inval, opc1(ctx.opcode),
opc2(ctx.opcode), opc3(ctx.opcode),
ctx.opcode, ctx.nip - 4);
} else {
printf("invalid bits: %08x for opcode: "
- "%02x -%02x - %02x (%08x) 0x" ADDRX "\n",
+ "%02x - %02x - %02x (%08x) 0x" ADDRX "\n",
ctx.opcode & handler->inval, opc1(ctx.opcode),
opc2(ctx.opcode), opc3(ctx.opcode),
ctx.opcode, ctx.nip - 4);
}
- RET_INVAL(ctxp);
+ GEN_EXCP_INVAL(ctxp);
break;
}
}
handler->count++;
#endif
/* Check trace mode exceptions */
- if (unlikely((msr_be && ctx.exception == EXCP_BRANCH) ||
- /* Check in single step trace mode
- * we need to stop except if:
- * - rfi, trap or syscall
- * - first instruction of an exception handler
- */
- (msr_se && (ctx.nip < 0x100 ||
- ctx.nip > 0xF00 ||
- (ctx.nip & 0xFC) != 0x04) &&
- ctx.exception != EXCP_SYSCALL &&
- ctx.exception != EXCP_SYSCALL_USER &&
- ctx.exception != EXCP_TRAP))) {
- RET_EXCP(ctxp, EXCP_TRACE, 0);
- }
- /* if we reach a page boundary or are single stepping, stop
- * generation
- */
- if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
- (env->singlestep_enabled))) {
+ if (unlikely(branch_step != 0 &&
+ ctx.exception == POWERPC_EXCP_BRANCH)) {
+ GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0);
+ } else if (unlikely(single_step != 0 &&
+ (ctx.nip <= 0x100 || ctx.nip > 0xF00 ||
+ (ctx.nip & 0xFC) != 0x04) &&
+ ctx.exception != POWERPC_SYSCALL &&
+ ctx.exception != POWERPC_EXCP_TRAP)) {
+ GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0);
+ } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
+ (env->singlestep_enabled))) {
+ /* if we reach a page boundary or are single stepping, stop
+ * generation
+ */
break;
}
#if defined (DO_SINGLE_STEP)
break;
#endif
}
- if (ctx.exception == EXCP_NONE) {
+ if (ctx.exception == POWERPC_EXCP_NONE) {
gen_goto_tb(&ctx, 0, ctx.nip);
- } else if (ctx.exception != EXCP_BRANCH) {
+ } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
gen_op_reset_T0();
/* Generate the return instruction */
gen_op_exit_tb();
lj++;
while (lj <= j)
gen_opc_instr_start[lj++] = 0;
- tb->size = 0;
} else {
tb->size = ctx.nip - pc_start;
}
}
if (loglevel & CPU_LOG_TB_IN_ASM) {
int flags;
- flags = msr_le;
+ flags = env->bfd_mach;
+ flags |= msr_le << 16;
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
fprintf(logfile, "\n");