return;
cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+ tcg_ctx.tcg_env = cpu_env;
p = cpu_reg_names;
cpu_reg_names_size = sizeof(cpu_reg_names);
uint32_t opcode;
uint32_t exception;
/* Routine used to access memory */
- bool pr, hv;
+ bool pr, hv, dr, le_mode;
+ bool lazy_tlb_flush;
int mem_idx;
int access_type;
/* Translation flags */
- int le_mode;
TCGMemOp default_tcg_memop_mask;
#if defined(TARGET_PPC64)
- int sf_mode;
- int has_cfar;
-#endif
- int fpu_enabled;
- int altivec_enabled;
- int vsx_enabled;
- int spe_enabled;
- int tm_enabled;
+ bool sf_mode;
+ bool has_cfar;
+#endif
+ bool fpu_enabled;
+ bool altivec_enabled;
+ bool vsx_enabled;
+ bool spe_enabled;
+ bool tm_enabled;
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled;
uint64_t insns_flags;
tcg_gen_movi_tl(cpu_nip, ctx->nip);
}
-static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
+static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
{
TCGv_i32 t0, t1;
if (ctx->exception == POWERPC_EXCP_NONE) {
ctx->exception = (excp);
}
-static inline void gen_exception(DisasContext *ctx, uint32_t excp)
+static void gen_exception(DisasContext *ctx, uint32_t excp)
{
TCGv_i32 t0;
if (ctx->exception == POWERPC_EXCP_NONE) {
ctx->exception = (excp);
}
-static inline void gen_debug_exception(DisasContext *ctx)
+static void gen_debug_exception(DisasContext *ctx)
{
TCGv_i32 t0;
static inline void gen_inval_exception(DisasContext *ctx, uint32_t error)
{
- gen_exception_err(ctx, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | error);
+ /* Will be converted to program check if needed */
+ gen_exception_err(ctx, POWERPC_EXCP_HV_EMU, POWERPC_EXCP_INVAL | error);
+}
+
+static inline void gen_priv_exception(DisasContext *ctx, uint32_t error)
+{
+ gen_exception_err(ctx, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_PRIV | error);
+}
+
+static inline void gen_hvpriv_exception(DisasContext *ctx, uint32_t error)
+{
+ /* Will be converted to program check if needed */
+ gen_exception_err(ctx, POWERPC_EXCP_HV_EMU, POWERPC_EXCP_PRIV | error);
}
/* Stop translation */
const char *oname;
} opcode_t;
+/* Helpers for priv. check */
+#define GEN_PRIV \
+ do { \
+ gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; \
+ } while (0)
+
+#if defined(CONFIG_USER_ONLY)
+#define CHK_HV GEN_PRIV
+#define CHK_SV GEN_PRIV
+#define CHK_HVRM GEN_PRIV
+#else
+#define CHK_HV \
+ do { \
+ if (unlikely(ctx->pr || !ctx->hv)) { \
+ GEN_PRIV; \
+ } \
+ } while (0)
+#define CHK_SV \
+ do { \
+ if (unlikely(ctx->pr)) { \
+ GEN_PRIV; \
+ } \
+ } while (0)
+#define CHK_HVRM \
+ do { \
+ if (unlikely(ctx->pr || !ctx->hv || ctx->dr)) { \
+ GEN_PRIV; \
+ } \
+ } while (0)
+#endif
+
+#define CHK_NONE
+
+
/*****************************************************************************/
/*** Instruction decoding ***/
#define EXTRACT_HELPER(name, shift, nb) \
return (((opcode >> (shift1)) & ((1 << (nb1)) - 1)) << nb2) | \
((opcode >> (shift2)) & ((1 << (nb2)) - 1)); \
}
+
+#define EXTRACT_HELPER_DXFORM(name, \
+ d0_bits, shift_op_d0, shift_d0, \
+ d1_bits, shift_op_d1, shift_d1, \
+ d2_bits, shift_op_d2, shift_d2) \
+static inline int16_t name(uint32_t opcode) \
+{ \
+ return \
+ (((opcode >> (shift_op_d0)) & ((1 << (d0_bits)) - 1)) << (shift_d0)) | \
+ (((opcode >> (shift_op_d1)) & ((1 << (d1_bits)) - 1)) << (shift_d1)) | \
+ (((opcode >> (shift_op_d2)) & ((1 << (d2_bits)) - 1)) << (shift_d2)); \
+}
+
+
/* Opcode part 1 */
EXTRACT_HELPER(opc1, 26, 6);
/* Opcode part 2 */
EXTRACT_HELPER(FPFLM, 17, 8);
EXTRACT_HELPER(FPW, 16, 1);
+/* addpcis */
+EXTRACT_HELPER_DXFORM(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0)
+
/*** Jump target decoding ***/
/* Immediate address */
static inline target_ulong LI(uint32_t opcode)
}
}
+/* cmprb - range comparison: isupper, isaplha, islower*/
+static void gen_cmprb(DisasContext *ctx)
+{
+ TCGv_i32 src1 = tcg_temp_new_i32();
+ TCGv_i32 src2 = tcg_temp_new_i32();
+ TCGv_i32 src2lo = tcg_temp_new_i32();
+ TCGv_i32 src2hi = tcg_temp_new_i32();
+ TCGv_i32 crf = cpu_crf[crfD(ctx->opcode)];
+
+ tcg_gen_trunc_tl_i32(src1, cpu_gpr[rA(ctx->opcode)]);
+ tcg_gen_trunc_tl_i32(src2, cpu_gpr[rB(ctx->opcode)]);
+
+ tcg_gen_andi_i32(src1, src1, 0xFF);
+ tcg_gen_ext8u_i32(src2lo, src2);
+ tcg_gen_shri_i32(src2, src2, 8);
+ tcg_gen_ext8u_i32(src2hi, src2);
+
+ tcg_gen_setcond_i32(TCG_COND_LEU, src2lo, src2lo, src1);
+ tcg_gen_setcond_i32(TCG_COND_LEU, src2hi, src1, src2hi);
+ tcg_gen_and_i32(crf, src2lo, src2hi);
+
+ if (ctx->opcode & 0x00200000) {
+ tcg_gen_shri_i32(src2, src2, 8);
+ tcg_gen_ext8u_i32(src2lo, src2);
+ tcg_gen_shri_i32(src2, src2, 8);
+ tcg_gen_ext8u_i32(src2hi, src2);
+ tcg_gen_setcond_i32(TCG_COND_LEU, src2lo, src2lo, src1);
+ tcg_gen_setcond_i32(TCG_COND_LEU, src2hi, src1, src2hi);
+ tcg_gen_and_i32(src2lo, src2lo, src2hi);
+ tcg_gen_or_i32(crf, crf, src2lo);
+ }
+ tcg_gen_shli_i32(crf, crf, CRF_GT);
+ tcg_temp_free_i32(src1);
+ tcg_temp_free_i32(src2);
+ tcg_temp_free_i32(src2lo);
+ tcg_temp_free_i32(src2hi);
+}
+
/* isel (PowerPC 2.03 specification) */
static void gen_isel(DisasContext *ctx)
{
}
}
+/* addpcis */
+static void gen_addpcis(DisasContext *ctx)
+{
+ target_long d = DX(ctx->opcode);
+
+ tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], ctx->nip + (d << 16));
+}
+
static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1,
TCGv arg2, int sign, int compute_ov)
{
GEN_DIVE(divdeo, divde, 1);
#endif
+static inline void gen_op_arith_modw(DisasContext *ctx, TCGv ret, TCGv arg1,
+ TCGv arg2, int sign)
+{
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i32 t1 = tcg_temp_new_i32();
+
+ tcg_gen_trunc_tl_i32(t0, arg1);
+ tcg_gen_trunc_tl_i32(t1, arg2);
+ if (sign) {
+ TCGv_i32 t2 = tcg_temp_new_i32();
+ TCGv_i32 t3 = tcg_temp_new_i32();
+ tcg_gen_setcondi_i32(TCG_COND_EQ, t2, t0, INT_MIN);
+ tcg_gen_setcondi_i32(TCG_COND_EQ, t3, t1, -1);
+ tcg_gen_and_i32(t2, t2, t3);
+ tcg_gen_setcondi_i32(TCG_COND_EQ, t3, t1, 0);
+ tcg_gen_or_i32(t2, t2, t3);
+ tcg_gen_movi_i32(t3, 0);
+ tcg_gen_movcond_i32(TCG_COND_NE, t1, t2, t3, t2, t1);
+ tcg_gen_rem_i32(t3, t0, t1);
+ tcg_gen_ext_i32_tl(ret, t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t3);
+ } else {
+ TCGv_i32 t2 = tcg_const_i32(1);
+ TCGv_i32 t3 = tcg_const_i32(0);
+ tcg_gen_movcond_i32(TCG_COND_EQ, t1, t1, t3, t2, t1);
+ tcg_gen_remu_i32(t3, t0, t1);
+ tcg_gen_extu_i32_tl(ret, t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t3);
+ }
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+}
+
+#define GEN_INT_ARITH_MODW(name, opc3, sign) \
+static void glue(gen_, name)(DisasContext *ctx) \
+{ \
+ gen_op_arith_modw(ctx, cpu_gpr[rD(ctx->opcode)], \
+ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \
+ sign); \
+}
+
+GEN_INT_ARITH_MODW(moduw, 0x08, 0);
+GEN_INT_ARITH_MODW(modsw, 0x18, 1);
+
/* mulhw mulhw. */
static void gen_mulhw(DisasContext *ctx)
{
/* nor & nor. */
GEN_LOGICAL2(nor, tcg_gen_nor_tl, 0x03, PPC_INTEGER);
-#if defined(TARGET_PPC64)
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
static void gen_pause(DisasContext *ctx)
{
TCGv_i32 t0 = tcg_const_i32(0);
} else if (unlikely(Rc(ctx->opcode) != 0)) {
gen_set_Rc0(ctx, cpu_gpr[rs]);
#if defined(TARGET_PPC64)
- } else {
+ } else if (rs != 0) { /* 0 is nop */
int prio = 0;
switch (rs) {
break;
#endif
default:
- /* nop */
break;
}
if (prio) {
tcg_gen_ori_tl(t0, t0, ((uint64_t)prio) << 50);
gen_store_spr(SPR_PPR, t0);
tcg_temp_free(t0);
- /* Pause us out of TCG otherwise spin loops with smt_low
- * eat too much CPU and the kernel hangs
- */
- gen_pause(ctx);
}
+#if !defined(CONFIG_USER_ONLY)
+ /* Pause out of TCG otherwise spin loops with smt_low eat too much
+ * CPU and the kernel hangs. This applies to all encodings other
+ * than no-op, e.g., miso(rs=26), yield(27), mdoio(29), mdoom(30),
+ * and all currently undefined.
+ */
+ gen_pause(ctx);
+#endif
#endif
}
}
tcg_gen_deposit_tl(t_ra, t_ra, t_rs, sh, me - mb + 1);
} else {
target_ulong mask;
- TCGv_i32 t0;
TCGv t1;
#if defined(TARGET_PPC64)
#endif
mask = MASK(mb, me);
- t0 = tcg_temp_new_i32();
t1 = tcg_temp_new();
- tcg_gen_trunc_tl_i32(t0, t_rs);
- tcg_gen_rotli_i32(t0, t0, sh);
- tcg_gen_extu_i32_tl(t1, t0);
- tcg_temp_free_i32(t0);
+ if (mask <= 0xffffffffu) {
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ tcg_gen_trunc_tl_i32(t0, t_rs);
+ tcg_gen_rotli_i32(t0, t0, sh);
+ tcg_gen_extu_i32_tl(t1, t0);
+ tcg_temp_free_i32(t0);
+ } else {
+#if defined(TARGET_PPC64)
+ tcg_gen_deposit_i64(t1, t_rs, t_rs, 32, 32);
+ tcg_gen_rotli_i64(t1, t1, sh);
+#else
+ g_assert_not_reached();
+#endif
+ }
tcg_gen_andi_tl(t1, t1, mask);
tcg_gen_andi_tl(t_ra, t_ra, ~mask);
tcg_gen_ext32u_tl(t_ra, t_rs);
tcg_gen_shri_tl(t_ra, t_ra, mb);
} else {
+ target_ulong mask;
#if defined(TARGET_PPC64)
mb += 32;
me += 32;
#endif
- if (sh == 0) {
- tcg_gen_andi_tl(t_ra, t_rs, MASK(mb, me));
- } else {
- TCGv_i32 t0 = tcg_temp_new_i32();
+ mask = MASK(mb, me);
+ if (mask <= 0xffffffffu) {
+ TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(t0, t_rs);
tcg_gen_rotli_i32(t0, t0, sh);
- tcg_gen_andi_i32(t0, t0, MASK(mb, me));
+ tcg_gen_andi_i32(t0, t0, mask);
tcg_gen_extu_i32_tl(t_ra, t0);
tcg_temp_free_i32(t0);
+ } else {
+#if defined(TARGET_PPC64)
+ tcg_gen_deposit_i64(t_ra, t_rs, t_rs, 32, 32);
+ tcg_gen_rotli_i64(t_ra, t_ra, sh);
+ tcg_gen_andi_i64(t_ra, t_ra, mask);
+#else
+ g_assert_not_reached();
+#endif
}
}
if (unlikely(Rc(ctx->opcode) != 0)) {
TCGv t_rb = cpu_gpr[rB(ctx->opcode)];
uint32_t mb = MB(ctx->opcode);
uint32_t me = ME(ctx->opcode);
- TCGv_i32 t0, t1;
+ target_ulong mask;
#if defined(TARGET_PPC64)
mb += 32;
me += 32;
#endif
+ mask = MASK(mb, me);
- t0 = tcg_temp_new_i32();
- t1 = tcg_temp_new_i32();
- tcg_gen_trunc_tl_i32(t0, t_rb);
- tcg_gen_trunc_tl_i32(t1, t_rs);
- tcg_gen_andi_i32(t0, t0, 0x1f);
- tcg_gen_rotl_i32(t1, t1, t0);
- tcg_temp_free_i32(t0);
+ if (mask <= 0xffffffffu) {
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i32 t1 = tcg_temp_new_i32();
+ tcg_gen_trunc_tl_i32(t0, t_rb);
+ tcg_gen_trunc_tl_i32(t1, t_rs);
+ tcg_gen_andi_i32(t0, t0, 0x1f);
+ tcg_gen_rotl_i32(t1, t1, t0);
+ tcg_gen_extu_i32_tl(t_ra, t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+ } else {
+#if defined(TARGET_PPC64)
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ tcg_gen_andi_i64(t0, t_rb, 0x1f);
+ tcg_gen_deposit_i64(t_ra, t_rs, t_rs, 32, 32);
+ tcg_gen_rotl_i64(t_ra, t_ra, t0);
+ tcg_temp_free_i64(t0);
+#else
+ g_assert_not_reached();
+#endif
+ }
- tcg_gen_andi_i32(t1, t1, MASK(mb, me));
- tcg_gen_extu_i32_tl(t_ra, t1);
- tcg_temp_free_i32(t1);
+ tcg_gen_andi_tl(t_ra, t_ra, mask);
if (unlikely(Rc(ctx->opcode) != 0)) {
gen_set_Rc0(ctx, t_ra);
tcg_temp_free(EA); \
}
-#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2) \
+#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2, chk) \
static void glue(gen_, name##x)(DisasContext *ctx) \
{ \
TCGv EA; \
+ chk; \
gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA); \
tcg_temp_free(EA); \
}
+
#define GEN_LDX(name, ldop, opc2, opc3, type) \
- GEN_LDX_E(name, ldop, opc2, opc3, type, PPC_NONE)
+ GEN_LDX_E(name, ldop, opc2, opc3, type, PPC_NONE, CHK_NONE)
+
+#define GEN_LDX_HVRM(name, ldop, opc2, opc3, type) \
+ GEN_LDX_E(name, ldop, opc2, opc3, type, PPC_NONE, CHK_HVRM)
#define GEN_LDS(name, ldop, op, type) \
GEN_LD(name, ldop, op | 0x20, type); \
/* ldx */
GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B);
+/* CI load/store variants */
+GEN_LDX_HVRM(ldcix, ld64, 0x15, 0x1b, PPC_CILDST)
+GEN_LDX_HVRM(lwzcix, ld32u, 0x15, 0x15, PPC_CILDST)
+GEN_LDX_HVRM(lhzcix, ld16u, 0x15, 0x19, PPC_CILDST)
+GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST)
+
static void gen_ld(DisasContext *ctx)
{
TCGv EA;
bool le_is_supported = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
if (!legal_in_user_mode && ctx->pr) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
tcg_temp_free(EA); \
}
-#define GEN_STX_E(name, stop, opc2, opc3, type, type2) \
+#define GEN_STX_E(name, stop, opc2, opc3, type, type2, chk) \
static void glue(gen_, name##x)(DisasContext *ctx) \
{ \
TCGv EA; \
+ chk; \
gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
tcg_temp_free(EA); \
}
#define GEN_STX(name, stop, opc2, opc3, type) \
- GEN_STX_E(name, stop, opc2, opc3, type, PPC_NONE)
+ GEN_STX_E(name, stop, opc2, opc3, type, PPC_NONE, CHK_NONE)
+
+#define GEN_STX_HVRM(name, stop, opc2, opc3, type) \
+ GEN_STX_E(name, stop, opc2, opc3, type, PPC_NONE, CHK_HVRM)
#define GEN_STS(name, stop, op, type) \
GEN_ST(name, stop, op | 0x20, type); \
#if defined(TARGET_PPC64)
GEN_STUX(std, st64, 0x15, 0x05, PPC_64B);
GEN_STX(std, st64, 0x15, 0x04, PPC_64B);
+GEN_STX_HVRM(stdcix, st64, 0x15, 0x1f, PPC_CILDST)
+GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST)
+GEN_STX_HVRM(sthcix, st16, 0x15, 0x1d, PPC_CILDST)
+GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST)
static void gen_std(DisasContext *ctx)
{
rs = rS(ctx->opcode);
if ((ctx->opcode & 0x3) == 0x2) { /* stq */
-
bool legal_in_user_mode = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
bool le_is_supported = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
+ if (!(ctx->insns_flags & PPC_64BX)) {
+ gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+ }
+
if (!legal_in_user_mode && ctx->pr) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP);
tcg_gen_qemu_ld_i64(arg1, arg2, ctx->mem_idx, op);
}
-GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX);
+GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE);
#endif /* TARGET_PPC64 */
/* sthbrx */
TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP);
tcg_gen_qemu_st_i64(arg1, arg2, ctx->mem_idx, op);
}
-GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX);
+GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE);
#endif /* TARGET_PPC64 */
/*** Integer load and store multiple ***/
{
}
-#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
+#if !defined(CONFIG_USER_ONLY)
static inline void gen_check_tlb_flush(DisasContext *ctx)
{
- TCGv_i32 t = tcg_temp_new_i32();
- TCGLabel *l = gen_new_label();
+ TCGv_i32 t;
+ TCGLabel *l;
+ if (!ctx->lazy_tlb_flush) {
+ return;
+ }
+ l = gen_new_label();
+ t = tcg_temp_new_i32();
tcg_gen_ld_i32(t, cpu_env, offsetof(CPUPPCState, tlb_need_flush));
tcg_gen_brcondi_i32(TCG_COND_EQ, t, 0, l);
gen_helper_check_tlb_flush(cpu_env);
uint32_t l = (ctx->opcode >> 21) & 3;
/*
- * For l == 2, it's a ptesync, We need to check for a pending TLB flush.
- * This can only happen in kernel mode however so check MSR_PR as well.
+ * We may need to check for a pending TLB flush.
+ *
+ * We do this on ptesync (l == 2) on ppc64 and any sync pn ppc32.
+ *
+ * Additionally, this can only happen in kernel mode however so
+ * check MSR_PR as well.
*/
- if (l == 2 && !ctx->pr) {
+ if (((l == 2) || !(ctx->insns_flags & PPC_64B)) && !ctx->pr) {
gen_check_tlb_flush(ctx);
}
}
/* wait */
static void gen_wait(DisasContext *ctx)
{
- TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i32 t0 = tcg_const_i32(1);
tcg_gen_st_i32(t0, cpu_env,
-offsetof(PowerPCCPU, env) + offsetof(CPUState, halted));
tcg_temp_free_i32(t0);
gen_exception_err(ctx, EXCP_HLT, 1);
}
+#if defined(TARGET_PPC64)
+static void gen_doze(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_PRIV;
+#else
+ TCGv_i32 t;
+
+ CHK_HV;
+ t = tcg_const_i32(PPC_PM_DOZE);
+ gen_helper_pminsn(cpu_env, t);
+ tcg_temp_free_i32(t);
+ gen_stop_exception(ctx);
+#endif /* defined(CONFIG_USER_ONLY) */
+}
+
+static void gen_nap(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_PRIV;
+#else
+ TCGv_i32 t;
+
+ CHK_HV;
+ t = tcg_const_i32(PPC_PM_NAP);
+ gen_helper_pminsn(cpu_env, t);
+ tcg_temp_free_i32(t);
+ gen_stop_exception(ctx);
+#endif /* defined(CONFIG_USER_ONLY) */
+}
+
+static void gen_sleep(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_PRIV;
+#else
+ TCGv_i32 t;
+
+ CHK_HV;
+ t = tcg_const_i32(PPC_PM_SLEEP);
+ gen_helper_pminsn(cpu_env, t);
+ tcg_temp_free_i32(t);
+ gen_stop_exception(ctx);
+#endif /* defined(CONFIG_USER_ONLY) */
+}
+
+static void gen_rvwinkle(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_PRIV;
+#else
+ TCGv_i32 t;
+
+ CHK_HV;
+ t = tcg_const_i32(PPC_PM_RVWINKLE);
+ gen_helper_pminsn(cpu_env, t);
+ tcg_temp_free_i32(t);
+ gen_stop_exception(ctx);
+#endif /* defined(CONFIG_USER_ONLY) */
+}
+#endif /* #if defined(TARGET_PPC64) */
+
/*** Floating-point load ***/
#define GEN_LDF(name, ldop, opc, type) \
static void glue(gen_, name)(DisasContext *ctx) \
static void gen_rfi(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
+ /* FIXME: This instruction doesn't exist anymore on 64-bit server
+ * processors compliant with arch 2.x, we should remove it there,
+ * but we need to fix OpenBIOS not to use it on 970 first
+ */
/* Restore CPU state */
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
gen_update_cfar(ctx, ctx->nip);
gen_helper_rfi(cpu_env);
gen_sync_exception(ctx);
static void gen_rfid(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
/* Restore CPU state */
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
gen_update_cfar(ctx, ctx->nip);
gen_helper_rfid(cpu_env);
gen_sync_exception(ctx);
static void gen_hrfid(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
/* Restore CPU state */
- if (unlikely(!ctx->hv)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_HV;
gen_helper_hrfid(cpu_env);
gen_sync_exception(ctx);
#endif
/* mfmsr */
static void gen_mfmsr(DisasContext *ctx)
{
-#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
-#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+ CHK_SV;
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_msr);
-#endif
}
static void spr_noaccess(DisasContext *ctx, int gprn, int sprn)
TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
}
}
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG);
}
} else {
+ /* ISA 2.07 defines these as no-ops */
+ if ((ctx->insns_flags2 & PPC2_ISA207S) &&
+ (sprn >= 808 && sprn <= 811)) {
+ /* This is a nop */
+ return;
+ }
/* Not defined */
fprintf(stderr, "Trying to read invalid spr %d (0x%03x) at "
TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
qemu_log("Trying to read invalid spr %d (0x%03x) at "
TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
}
- gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+
+ /* The behaviour depends on MSR:PR and SPR# bit 0x10,
+ * it can generate a priv, a hv emu or a no-op
+ */
+ if (sprn & 0x10) {
+ if (ctx->pr) {
+ gen_priv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+ }
+ } else {
+ if (ctx->pr || sprn == 0 || sprn == 4 || sprn == 5 || sprn == 6) {
+ gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+ }
+ }
}
}
#if defined(TARGET_PPC64)
static void gen_mtmsrd(DisasContext *ctx)
{
-#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
-#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+ CHK_SV;
+
+#if !defined(CONFIG_USER_ONLY)
if (ctx->opcode & 0x00010000) {
/* Special form that does not need any synchronisation */
TCGv t0 = tcg_temp_new();
/* Note that mtmsr is not always defined as context-synchronizing */
gen_stop_exception(ctx);
}
-#endif
+#endif /* !defined(CONFIG_USER_ONLY) */
}
-#endif
+#endif /* defined(TARGET_PPC64) */
static void gen_mtmsr(DisasContext *ctx)
{
-#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
-#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
- if (ctx->opcode & 0x00010000) {
+ CHK_SV;
+
+#if !defined(CONFIG_USER_ONLY)
+ if (ctx->opcode & 0x00010000) {
/* Special form that does not need any synchronisation */
TCGv t0 = tcg_temp_new();
tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE));
qemu_log("Trying to write privileged spr %d (0x%03x) at "
TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
}
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG);
}
} else {
+ /* ISA 2.07 defines these as no-ops */
+ if ((ctx->insns_flags2 & PPC2_ISA207S) &&
+ (sprn >= 808 && sprn <= 811)) {
+ /* This is a nop */
+ return;
+ }
+
/* Not defined */
if (qemu_log_separate()) {
qemu_log("Trying to write invalid spr %d (0x%03x) at "
}
fprintf(stderr, "Trying to write invalid spr %d (0x%03x) at "
TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);
- gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+
+
+ /* The behaviour depends on MSR:PR and SPR# bit 0x10,
+ * it can generate a priv, a hv emu or a no-op
+ */
+ if (sprn & 0x10) {
+ if (ctx->pr) {
+ gen_priv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+ }
+ } else {
+ if (ctx->pr || sprn == 0) {
+ gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+ }
+ }
}
}
static void gen_dcbi(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
TCGv EA, val;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+
+ CHK_SV;
EA = tcg_temp_new();
gen_set_access_type(ctx, ACCESS_CACHE);
gen_addr_reg_index(ctx, EA);
gen_qemu_st8(ctx, val, EA);
tcg_temp_free(val);
tcg_temp_free(EA);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* dcdst */
static void gen_mfsr(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+
+ CHK_SV;
t0 = tcg_const_tl(SR(ctx->opcode));
gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* mfsrin */
static void gen_mfsrin(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+
+ CHK_SV;
t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
tcg_gen_andi_tl(t0, t0, 0xF);
gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* mtsr */
static void gen_mtsr(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+
+ CHK_SV;
t0 = tcg_const_tl(SR(ctx->opcode));
gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* mtsrin */
static void gen_mtsrin(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+ CHK_SV;
+
t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
tcg_gen_andi_tl(t0, t0, 0xF);
gen_helper_store_sr(cpu_env, t0, cpu_gpr[rD(ctx->opcode)]);
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
#if defined(TARGET_PPC64)
static void gen_mfsr_64b(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+
+ CHK_SV;
t0 = tcg_const_tl(SR(ctx->opcode));
gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* mfsrin */
static void gen_mfsrin_64b(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+
+ CHK_SV;
t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
tcg_gen_andi_tl(t0, t0, 0xF);
gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* mtsr */
static void gen_mtsr_64b(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+
+ CHK_SV;
t0 = tcg_const_tl(SR(ctx->opcode));
gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* mtsrin */
static void gen_mtsrin_64b(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+
+ CHK_SV;
t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
tcg_gen_andi_tl(t0, t0, 0xF);
gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* slbmte */
static void gen_slbmte(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+ CHK_SV;
+
gen_helper_store_slb(cpu_env, cpu_gpr[rB(ctx->opcode)],
cpu_gpr[rS(ctx->opcode)]);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
static void gen_slbmfee(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+ CHK_SV;
+
gen_helper_load_slb_esid(cpu_gpr[rS(ctx->opcode)], cpu_env,
cpu_gpr[rB(ctx->opcode)]);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
static void gen_slbmfev(DisasContext *ctx)
{
+#if defined(CONFIG_USER_ONLY)
+ GEN_PRIV;
+#else
+ CHK_SV;
+
+ gen_helper_load_slb_vsid(cpu_gpr[rS(ctx->opcode)], cpu_env,
+ cpu_gpr[rB(ctx->opcode)]);
+#endif /* defined(CONFIG_USER_ONLY) */
+}
+
+static void gen_slbfee_(DisasContext *ctx)
+{
#if defined(CONFIG_USER_ONLY)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
#else
+ TCGLabel *l1, *l2;
+
if (unlikely(ctx->pr)) {
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
return;
}
- gen_helper_load_slb_vsid(cpu_gpr[rS(ctx->opcode)], cpu_env,
+ gen_helper_find_slb_vsid(cpu_gpr[rS(ctx->opcode)], cpu_env,
cpu_gpr[rB(ctx->opcode)]);
+ l1 = gen_new_label();
+ l2 = gen_new_label();
+ tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rS(ctx->opcode)], -1, l1);
+ tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
+ tcg_gen_br(l2);
+ gen_set_label(l1);
+ tcg_gen_movi_tl(cpu_gpr[rS(ctx->opcode)], 0);
+ gen_set_label(l2);
#endif
}
#endif /* defined(TARGET_PPC64) */
static void gen_tlbia(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_HV;
+
gen_helper_tlbia(cpu_env);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* tlbiel */
static void gen_tlbiel(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
+
gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* tlbie */
static void gen_tlbie(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr || !ctx->hv)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_HV;
+
if (NARROW_MODE(ctx)) {
TCGv t0 = tcg_temp_new();
tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]);
} else {
gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]);
}
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* tlbsync */
static void gen_tlbsync(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr || !ctx->hv)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_HV;
+
/* tlbsync is a nop for server, ptesync handles delayed tlb flush,
* embedded however needs to deal with tlbsync. We don't try to be
* fancy and swallow the overhead of checking for both.
*/
gen_check_tlb_flush(ctx);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
#if defined(TARGET_PPC64)
static void gen_slbia(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr || !ctx->hv)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
+
gen_helper_slbia(cpu_env);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* slbie */
static void gen_slbie(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
+
gen_helper_slbie(cpu_env, cpu_gpr[rB(ctx->opcode)]);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
-#endif
+#endif /* defined(TARGET_PPC64) */
/*** External control ***/
/* Optional: */
static void gen_mfrom(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
gen_helper_602_mfrom(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* 602 - 603 - G2 TLB management */
static void gen_tlbld_6xx(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
gen_helper_6xx_tlbd(cpu_env, cpu_gpr[rB(ctx->opcode)]);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* tlbli */
static void gen_tlbli_6xx(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
gen_helper_6xx_tlbi(cpu_env, cpu_gpr[rB(ctx->opcode)]);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* 74xx TLB management */
static void gen_tlbld_74xx(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
gen_helper_74xx_tlbd(cpu_env, cpu_gpr[rB(ctx->opcode)]);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* tlbli */
static void gen_tlbli_74xx(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
gen_helper_74xx_tlbi(cpu_env, cpu_gpr[rB(ctx->opcode)]);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* POWER instructions not in PowerPC 601 */
/* cli */
static void gen_cli(DisasContext *ctx)
{
- /* Cache line invalidate: privileged and treated as no-op */
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
-#endif
+ /* Cache line invalidate: privileged and treated as no-op */
+ CHK_SV;
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* dclst */
static void gen_mfsri(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
int ra = rA(ctx->opcode);
int rd = rD(ctx->opcode);
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+
+ CHK_SV;
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
tcg_gen_shri_tl(t0, t0, 28);
tcg_temp_free(t0);
if (ra != 0 && ra != rd)
tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rd]);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
static void gen_rac(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+
+ CHK_SV;
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
gen_helper_rac(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
static void gen_rfsvc(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
+
gen_helper_rfsvc(cpu_env);
gen_sync_exception(ctx);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* svc is not implemented for now */
static void gen_tlbiva(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+
+ CHK_SV;
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
gen_helper_tlbiva(cpu_env, cpu_gpr[rB(ctx->opcode)]);
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* All 405 MAC instructions are translated here */
static void gen_mfdcr(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
TCGv dcrn;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+
+ CHK_SV;
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
dcrn = tcg_const_tl(SPR(ctx->opcode));
gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, dcrn);
tcg_temp_free(dcrn);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* mtdcr */
static void gen_mtdcr(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
TCGv dcrn;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+
+ CHK_SV;
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
dcrn = tcg_const_tl(SPR(ctx->opcode));
gen_helper_store_dcr(cpu_env, dcrn, cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free(dcrn);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* mfdcrx */
static void gen_mfdcrx(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+ CHK_SV;
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
cpu_gpr[rA(ctx->opcode)]);
/* Note: Rc update flag set leads to undefined state of Rc0 */
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* mtdcrx */
static void gen_mtdcrx(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
+ CHK_SV;
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
cpu_gpr[rS(ctx->opcode)]);
/* Note: Rc update flag set leads to undefined state of Rc0 */
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* mfdcrux (PPC 460) : user-mode access to DCR */
/* dccci */
static void gen_dccci(DisasContext *ctx)
{
-#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
-#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
/* interpreted as no-op */
-#endif
}
/* dcread */
static void gen_dcread(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
TCGv EA, val;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+
+ CHK_SV;
gen_set_access_type(ctx, ACCESS_CACHE);
EA = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
tcg_temp_free(val);
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], EA);
tcg_temp_free(EA);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* icbt */
/* iccci */
static void gen_iccci(DisasContext *ctx)
{
-#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
-#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
/* interpreted as no-op */
-#endif
}
/* icread */
static void gen_icread(DisasContext *ctx)
{
-#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
-#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
/* interpreted as no-op */
-#endif
}
/* rfci (supervisor only) */
static void gen_rfci_40x(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
/* Restore CPU state */
gen_helper_40x_rfci(cpu_env);
gen_sync_exception(ctx);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
static void gen_rfci(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
/* Restore CPU state */
gen_helper_rfci(cpu_env);
gen_sync_exception(ctx);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* BookE specific */
static void gen_rfdi(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
/* Restore CPU state */
gen_helper_rfdi(cpu_env);
gen_sync_exception(ctx);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* XXX: not implemented on 440 ? */
static void gen_rfmci(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
/* Restore CPU state */
gen_helper_rfmci(cpu_env);
gen_sync_exception(ctx);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* TLB management - PowerPC 405 implementation */
static void gen_tlbre_40x(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
switch (rB(ctx->opcode)) {
case 0:
gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_env,
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
break;
}
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* tlbsx - tlbsx. */
static void gen_tlbsx_40x(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+
+ CHK_SV;
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02);
gen_set_label(l1);
}
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* tlbwe */
static void gen_tlbwe_40x(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
+
switch (rB(ctx->opcode)) {
case 0:
gen_helper_4xx_tlbwe_hi(cpu_env, cpu_gpr[rA(ctx->opcode)],
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
break;
}
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* TLB management - PowerPC 440 implementation */
static void gen_tlbre_440(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
+
switch (rB(ctx->opcode)) {
case 0:
case 1:
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
break;
}
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* tlbsx - tlbsx. */
static void gen_tlbsx_440(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+
+ CHK_SV;
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02);
gen_set_label(l1);
}
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* tlbwe */
static void gen_tlbwe_440(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
switch (rB(ctx->opcode)) {
case 0:
case 1:
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
break;
}
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* TLB management - PowerPC BookE 2.06 implementation */
/* tlbre */
static void gen_tlbre_booke206(DisasContext *ctx)
{
-#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ #if defined(CONFIG_USER_ONLY)
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
-
+ CHK_SV;
gen_helper_booke206_tlbre(cpu_env);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* tlbsx - tlbsx. */
static void gen_tlbsx_booke206(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
if (rA(ctx->opcode)) {
t0 = tcg_temp_new();
tcg_gen_mov_tl(t0, cpu_gpr[rD(ctx->opcode)]);
tcg_gen_add_tl(t0, t0, cpu_gpr[rB(ctx->opcode)]);
gen_helper_booke206_tlbsx(cpu_env, t0);
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* tlbwe */
static void gen_tlbwe_booke206(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
gen_update_nip(ctx, ctx->nip - 4);
gen_helper_booke206_tlbwe(cpu_env);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
static void gen_tlbivax_booke206(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
-
gen_helper_booke206_tlbivax(cpu_env, t0);
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
static void gen_tlbilx_booke206(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
}
tcg_temp_free(t0);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
static void gen_wrtee(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+
+ CHK_SV;
t0 = tcg_temp_new();
tcg_gen_andi_tl(t0, cpu_gpr[rD(ctx->opcode)], (1 << MSR_EE));
tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
* if we just set msr_ee to 1
*/
gen_stop_exception(ctx);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* wrteei */
static void gen_wrteei(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
+ CHK_SV;
if (ctx->opcode & 0x00008000) {
tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE));
/* Stop translation to have a chance to raise an exception */
} else {
tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
}
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/* PowerPC 440 specific instructions */
static void gen_msgclr(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
-
+ CHK_SV;
gen_helper_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
static void gen_msgsnd(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ GEN_PRIV;
#else
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
- return;
- }
-
+ CHK_SV;
gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]);
-#endif
+#endif /* defined(CONFIG_USER_ONLY) */
}
/*** Altivec vector extension ***/
#define GEN_TM_PRIV_NOOP(name) \
static inline void gen_##name(DisasContext *ctx) \
{ \
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); \
+ gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); \
}
#else
#define GEN_TM_PRIV_NOOP(name) \
static inline void gen_##name(DisasContext *ctx) \
{ \
- if (unlikely(ctx->pr)) { \
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); \
- return; \
- } \
+ CHK_SV; \
if (unlikely(!ctx->tm_enabled)) { \
gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); \
return; \
GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER),
GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER),
GEN_HANDLER_E(cmpb, 0x1F, 0x1C, 0x0F, 0x00000001, PPC_NONE, PPC2_ISA205),
+GEN_HANDLER_E(cmprb, 0x1F, 0x00, 0x06, 0x00400001, PPC_NONE, PPC2_ISA300),
GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x00000001, PPC_ISEL),
GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
+GEN_HANDLER_E(addpcis, 0x13, 0x2, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300),
GEN_HANDLER(mulhw, 0x1F, 0x0B, 0x02, 0x00000400, PPC_INTEGER),
GEN_HANDLER(mulhwu, 0x1F, 0x0B, 0x00, 0x00000400, PPC_INTEGER),
GEN_HANDLER(mullw, 0x1F, 0x0B, 0x07, 0x00000000, PPC_INTEGER),
GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW),
#if defined(TARGET_PPC64)
GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B),
+GEN_HANDLER_E(doze, 0x13, 0x12, 0x0c, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
+GEN_HANDLER_E(nap, 0x13, 0x12, 0x0d, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
+GEN_HANDLER_E(sleep, 0x13, 0x12, 0x0e, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
+GEN_HANDLER_E(rvwinkle, 0x13, 0x12, 0x0f, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H),
#endif
GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW),
#if defined(TARGET_PPC64)
GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B),
#endif
-GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC),
+GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001EF801, PPC_MISC),
GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000000, PPC_MISC),
GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE),
GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE),
GEN_HANDLER2(slbmte, "slbmte", 0x1F, 0x12, 0x0C, 0x001F0001, PPC_SEGMENT_64B),
GEN_HANDLER2(slbmfee, "slbmfee", 0x1F, 0x13, 0x1C, 0x001F0001, PPC_SEGMENT_64B),
GEN_HANDLER2(slbmfev, "slbmfev", 0x1F, 0x13, 0x1A, 0x001F0001, PPC_SEGMENT_64B),
+GEN_HANDLER2(slbfee_, "slbfee.", 0x1F, 0x13, 0x1E, 0x001F0000, PPC_SEGMENT_64B),
#endif
GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA),
/* XXX Those instructions will need to be handled differently for
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x001F0001, PPC_MEM_TLBIE),
GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC),
#if defined(TARGET_PPC64)
-GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI),
+GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x031FFC01, PPC_SLBI),
GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI),
#endif
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN),
GEN_HANDLER_E(divweo, 0x1F, 0x0B, 0x1D, 0, PPC_NONE, PPC2_DIVE_ISA206),
GEN_HANDLER_E(divweu, 0x1F, 0x0B, 0x0C, 0, PPC_NONE, PPC2_DIVE_ISA206),
GEN_HANDLER_E(divweuo, 0x1F, 0x0B, 0x1C, 0, PPC_NONE, PPC2_DIVE_ISA206),
+GEN_HANDLER_E(modsw, 0x1F, 0x0B, 0x18, 0x00000001, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(moduw, 0x1F, 0x0B, 0x08, 0x00000001, PPC_NONE, PPC2_ISA300),
#if defined(TARGET_PPC64)
#undef GEN_INT_ARITH_DIVD
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type),
#define GEN_LDUX(name, ldop, opc2, opc3, type) \
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type),
-#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2) \
+#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2, chk) \
GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2),
#define GEN_LDS(name, ldop, op, type) \
GEN_LD(name, ldop, op | 0x20, type) \
GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B)
GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B)
GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B)
-GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX)
+GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE)
+
+/* HV/P7 and later only */
+GEN_LDX_HVRM(ldcix, ld64, 0x15, 0x1b, PPC_CILDST)
+GEN_LDX_HVRM(lwzcix, ld32u, 0x15, 0x18, PPC_CILDST)
+GEN_LDX_HVRM(lhzcix, ld16u, 0x15, 0x19, PPC_CILDST)
+GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST)
#endif
GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER)
GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER)
GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type),
#define GEN_STUX(name, stop, opc2, opc3, type) \
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type),
-#define GEN_STX_E(name, stop, opc2, opc3, type, type2) \
+#define GEN_STX_E(name, stop, opc2, opc3, type, type2, chk) \
GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2),
#define GEN_STS(name, stop, op, type) \
GEN_ST(name, stop, op | 0x20, type) \
#if defined(TARGET_PPC64)
GEN_STUX(std, st64, 0x15, 0x05, PPC_64B)
GEN_STX(std, st64, 0x15, 0x04, PPC_64B)
-GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX)
+GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE)
+GEN_STX_HVRM(stdcix, st64, 0x15, 0x1f, PPC_CILDST)
+GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST)
+GEN_STX_HVRM(sthcix, st16, 0x15, 0x1d, PPC_CILDST)
+GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST)
#endif
GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER)
GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER)
env->spr[SPR_SPRG4], env->spr[SPR_SPRG5],
env->spr[SPR_SPRG6], env->spr[SPR_SPRG7]);
+#if defined(TARGET_PPC64)
+ if (env->excp_model == POWERPC_EXCP_POWER7 ||
+ env->excp_model == POWERPC_EXCP_POWER8) {
+ cpu_fprintf(f, "HSRR0 " TARGET_FMT_lx " HSRR1 " TARGET_FMT_lx "\n",
+ env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
+ }
+#endif
if (env->excp_model == POWERPC_EXCP_BOOKE) {
cpu_fprintf(f, "CSRR0 " TARGET_FMT_lx " CSRR1 " TARGET_FMT_lx
" MCSRR0 " TARGET_FMT_lx " MCSRR1 " TARGET_FMT_lx "\n",
ctx.spr_cb = env->spr_cb;
ctx.pr = msr_pr;
ctx.mem_idx = env->dmmu_idx;
+ ctx.dr = msr_dr;
#if !defined(CONFIG_USER_ONLY)
ctx.hv = msr_hv || !env->has_hv_mode;
#endif
ctx.insns_flags = env->insns_flags;
ctx.insns_flags2 = env->insns_flags2;
ctx.access_type = -1;
- ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0;
+ ctx.le_mode = !!(env->hflags & (1 << MSR_LE));
ctx.default_tcg_memop_mask = ctx.le_mode ? MO_LE : MO_BE;
#if defined(TARGET_PPC64)
ctx.sf_mode = msr_is_64bit(env, env->msr);
ctx.has_cfar = !!(env->flags & POWERPC_FLAG_CFAR);
#endif
- ctx.fpu_enabled = msr_fp;
+ if (env->mmu_model == POWERPC_MMU_32B ||
+ env->mmu_model == POWERPC_MMU_601 ||
+ (env->mmu_model & POWERPC_MMU_64B))
+ ctx.lazy_tlb_flush = true;
+
+ ctx.fpu_enabled = !!msr_fp;
if ((env->flags & POWERPC_FLAG_SPE) && msr_spe)
- ctx.spe_enabled = msr_spe;
+ ctx.spe_enabled = !!msr_spe;
else
- ctx.spe_enabled = 0;
+ ctx.spe_enabled = false;
if ((env->flags & POWERPC_FLAG_VRE) && msr_vr)
- ctx.altivec_enabled = msr_vr;
+ ctx.altivec_enabled = !!msr_vr;
else
- ctx.altivec_enabled = 0;
+ ctx.altivec_enabled = false;
if ((env->flags & POWERPC_FLAG_VSX) && msr_vsx) {
- ctx.vsx_enabled = msr_vsx;
+ ctx.vsx_enabled = !!msr_vsx;
} else {
- ctx.vsx_enabled = 0;
+ ctx.vsx_enabled = false;
}
#if defined(TARGET_PPC64)
if ((env->flags & POWERPC_FLAG_TM) && msr_tm) {
- ctx.tm_enabled = msr_tm;
+ ctx.tm_enabled = !!msr_tm;
} else {
- ctx.tm_enabled = 0;
+ ctx.tm_enabled = false;
}
#endif
if ((env->flags & POWERPC_FLAG_SE) && msr_se)