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);
+}
+
+#if defined(TARGET_PPC64)
+/* cmpeqb */
+static void gen_cmpeqb(DisasContext *ctx)
+{
+ gen_helper_cmpeqb(cpu_crf[crfD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
+ cpu_gpr[rB(ctx->opcode)]);
+}
+#endif
+
/* 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);
+
+#if defined(TARGET_PPC64)
+static inline void gen_op_arith_modd(DisasContext *ctx, TCGv ret, TCGv arg1,
+ TCGv arg2, int sign)
+{
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+
+ tcg_gen_mov_i64(t0, arg1);
+ tcg_gen_mov_i64(t1, arg2);
+ if (sign) {
+ TCGv_i64 t2 = tcg_temp_new_i64();
+ TCGv_i64 t3 = tcg_temp_new_i64();
+ tcg_gen_setcondi_i64(TCG_COND_EQ, t2, t0, INT64_MIN);
+ tcg_gen_setcondi_i64(TCG_COND_EQ, t3, t1, -1);
+ tcg_gen_and_i64(t2, t2, t3);
+ tcg_gen_setcondi_i64(TCG_COND_EQ, t3, t1, 0);
+ tcg_gen_or_i64(t2, t2, t3);
+ tcg_gen_movi_i64(t3, 0);
+ tcg_gen_movcond_i64(TCG_COND_NE, t1, t2, t3, t2, t1);
+ tcg_gen_rem_i64(ret, t0, t1);
+ tcg_temp_free_i64(t2);
+ tcg_temp_free_i64(t3);
+ } else {
+ TCGv_i64 t2 = tcg_const_i64(1);
+ TCGv_i64 t3 = tcg_const_i64(0);
+ tcg_gen_movcond_i64(TCG_COND_EQ, t1, t1, t3, t2, t1);
+ tcg_gen_remu_i64(ret, t0, t1);
+ tcg_temp_free_i64(t2);
+ tcg_temp_free_i64(t3);
+ }
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+}
+
+#define GEN_INT_ARITH_MODD(name, opc3, sign) \
+static void glue(gen_, name)(DisasContext *ctx) \
+{ \
+ gen_op_arith_modd(ctx, cpu_gpr[rD(ctx->opcode)], \
+ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \
+ sign); \
+}
+
+GEN_INT_ARITH_MODD(modud, 0x08, 0);
+GEN_INT_ARITH_MODD(modsd, 0x18, 1);
+#endif
+
/* mulhw mulhw. */
static void gen_mulhw(DisasContext *ctx)
{
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
+
+/* cnttzw */
+static void gen_cnttzw(DisasContext *ctx)
+{
+ gen_helper_cnttzw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+ if (unlikely(Rc(ctx->opcode) != 0)) {
+ gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+ }
+}
+
/* eqv & eqv. */
GEN_LOGICAL2(eqv, tcg_gen_eqv_tl, 0x08, PPC_INTEGER);
/* extsb & extsb. */
} 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
- */
+ }
#if !defined(CONFIG_USER_ONLY)
- gen_pause(ctx);
+ /* 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
}
}
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
+
+/* cnttzd */
+static void gen_cnttzd(DisasContext *ctx)
+{
+ gen_helper_cnttzd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+ if (unlikely(Rc(ctx->opcode) != 0)) {
+ gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
+ }
+}
#endif
/*** Integer rotate ***/
}
}
+#if defined(TARGET_PPC64)
+/* setb */
+static void gen_setb(DisasContext *ctx)
+{
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i32 t8 = tcg_temp_new_i32();
+ TCGv_i32 tm1 = tcg_temp_new_i32();
+ int crf = crfS(ctx->opcode);
+
+ tcg_gen_setcondi_i32(TCG_COND_GEU, t0, cpu_crf[crf], 4);
+ tcg_gen_movi_i32(t8, 8);
+ tcg_gen_movi_i32(tm1, -1);
+ tcg_gen_movcond_i32(TCG_COND_GEU, t0, cpu_crf[crf], t8, tm1, t0);
+ tcg_gen_ext_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t8);
+ tcg_temp_free_i32(tm1);
+}
+#endif
+
/*** Cache management ***/
/* dcbf */
GEN_VAFORM_PAIRED(vsel, vperm, 21)
GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23)
+#if defined(TARGET_PPC64)
+static void gen_maddld(DisasContext *ctx)
+{
+ TCGv_i64 t1 = tcg_temp_new_i64();
+
+ tcg_gen_mul_i64(t1, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+ tcg_gen_add_i64(cpu_gpr[rD(ctx->opcode)], t1, cpu_gpr[rC(ctx->opcode)]);
+ tcg_temp_free_i64(t1);
+}
+
+/* maddhd maddhdu */
+static void gen_maddhd_maddhdu(DisasContext *ctx)
+{
+ TCGv_i64 lo = tcg_temp_new_i64();
+ TCGv_i64 hi = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+
+ if (Rc(ctx->opcode)) {
+ tcg_gen_mulu2_i64(lo, hi, cpu_gpr[rA(ctx->opcode)],
+ cpu_gpr[rB(ctx->opcode)]);
+ tcg_gen_movi_i64(t1, 0);
+ } else {
+ tcg_gen_muls2_i64(lo, hi, cpu_gpr[rA(ctx->opcode)],
+ cpu_gpr[rB(ctx->opcode)]);
+ tcg_gen_sari_i64(t1, cpu_gpr[rC(ctx->opcode)], 63);
+ }
+ tcg_gen_add2_i64(t1, cpu_gpr[rD(ctx->opcode)], lo, hi,
+ cpu_gpr[rC(ctx->opcode)], t1);
+ tcg_temp_free_i64(lo);
+ tcg_temp_free_i64(hi);
+ tcg_temp_free_i64(t1);
+}
+#endif /* defined(TARGET_PPC64) */
+
GEN_VXFORM_NOA(vclzb, 1, 28)
GEN_VXFORM_NOA(vclzh, 1, 29)
GEN_VXFORM_NOA(vclzw, 1, 30)
GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER),
GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER),
GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER),
+#if defined(TARGET_PPC64)
+GEN_HANDLER_E(cmpeqb, 0x1F, 0x00, 0x07, 0x00600000, PPC_NONE, PPC2_ISA300),
+#endif
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_HANDLER2(andi_, "andi.", 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER2(andis_, "andis.", 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(cntlzw, 0x1F, 0x1A, 0x00, 0x00000000, PPC_INTEGER),
+GEN_HANDLER_E(cnttzw, 0x1F, 0x1A, 0x10, 0x00000000, PPC_NONE, PPC2_ISA300),
GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER),
GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER),
GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
#if defined(TARGET_PPC64)
GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD),
GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B),
+GEN_HANDLER_E(cnttzd, 0x1F, 0x1A, 0x11, 0x00000000, PPC_NONE, PPC2_ISA300),
GEN_HANDLER_E(prtyd, 0x1F, 0x1A, 0x05, 0x0000F801, PPC_NONE, PPC2_ISA205),
GEN_HANDLER_E(bpermd, 0x1F, 0x1C, 0x07, 0x00000001, PPC_NONE, PPC2_PERM_ISA206),
#endif
GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC),
#if defined(TARGET_PPC64)
GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B),
+GEN_HANDLER_E(setb, 0x1F, 0x00, 0x04, 0x0003F801, PPC_NONE, PPC2_ISA300),
#endif
GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001EF801, PPC_MISC),
GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000000, PPC_MISC),
GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC),
GEN_HANDLER(mtvscr, 0x04, 0x2, 0x19, 0x03ff0000, PPC_ALTIVEC),
GEN_HANDLER(vmladduhm, 0x04, 0x11, 0xFF, 0x00000000, PPC_ALTIVEC),
+#if defined(TARGET_PPC64)
+GEN_HANDLER_E(maddhd_maddhdu, 0x04, 0x18, 0xFF, 0x00000000, PPC_NONE,
+ PPC2_ISA300),
+GEN_HANDLER_E(maddld, 0x04, 0x19, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300),
+#endif
GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE),
GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE),
GEN_HANDLER2(evsel2, "evsel", 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE),
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_E(divdeuo, 0x1F, 0x09, 0x1C, 0, PPC_NONE, PPC2_DIVE_ISA206),
GEN_HANDLER_E(divde, 0x1F, 0x09, 0x0D, 0, PPC_NONE, PPC2_DIVE_ISA206),
GEN_HANDLER_E(divdeo, 0x1F, 0x09, 0x1D, 0, PPC_NONE, PPC2_DIVE_ISA206),
+GEN_HANDLER_E(modsd, 0x1F, 0x09, 0x18, 0x00000001, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(modud, 0x1F, 0x09, 0x08, 0x00000001, PPC_NONE, PPC2_ISA300),
#undef GEN_INT_ARITH_MUL_HELPER
#define GEN_INT_ARITH_MUL_HELPER(name, opc3) \